通过上一篇 利用自定义Java注解实现资源注入 介绍的方法,我们实现了通过自定义注解完成了对DataSource资源的注入,但在实际应用中,我们通常不希望去显式的去声明这样的MyAnnotationBeanProcessor对象来帮助我们完成注入,而是希望通过Spring帮我们“悄悄地”完成。
利用自定义Java注解实现资源注入 里的代码(部分代码)不变,我们希望在测试类中以如下方法调用便可以实现资源的注入:
 

  1. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  2.  
  3. import com.annotation.MyService;  
  4.  
  5. public class SpringWiringTest {  
  6.     public static void main(String args[]) {  
  7.         ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("com/spring/applicationContext.xml");  
  8.         MyService b = (MyService)ctx.getBean("myService"); // 通过Spring去管理bean,此时已完成了对标有DataSource注解的资源的注入  
  9.         System.out.println(b.selectForObjectFromB(""null));  
  10.         System.out.println(b.selectForObjectFromA(""null));  
  11.     }  


注:MyService类实现在 利用自定义Java注解实现资源注入 中。

为了实现上面的目标,我们就不能使用MyAnnotationBeanProcessor.java类来实现对资源的注入了,我们必须实现一个能融入Spring的BeanProcessor类才行。
DataSourceBeanProcessor.java类实现BeanPostProcessor、PriorityOrdered接口:
 

  1. import java.lang.reflect.Field;  
  2.  
  3. import org.springframework.beans.BeansException;  
  4. import org.springframework.beans.factory.config.BeanPostProcessor;  
  5. import org.springframework.core.Ordered;  
  6. import org.springframework.core.PriorityOrdered;  
  7.  
  8. public class DataSourceBeanProcessor implements BeanPostProcessor, PriorityOrdered {  
  9.     @Override 
  10.     // 在这里完成资源注入  
  11.     public Object postProcessAfterInitialization(Object bean, String beanName)  
  12.         throws BeansException {  
  13.         Class<?> cls = bean.getClass();  
  14.         for (Field field : cls.getDeclaredFields()) {  
  15.             if (field.isAnnotationPresent(DataSource.class)) {  
  16.                 DataSourceStaticWiring.wiring(bean, field);  
  17.             }  
  18.         }  
  19.         return bean;  
  20.     }  
  21.  
  22.     @Override 
  23.     public Object postProcessBeforeInitialization(Object bean, String beanName)  
  24.         throws BeansException {  
  25.         return bean;  
  26.     }  
  27.  
  28.     @Override 
  29.     public int getOrder() {  
  30.         return Ordered.LOWEST_PRECEDENCE;  
  31.     }  


下面来看DataSourceStaticWiring的实现,与前一篇 里的DataSourceWiring.java类相比,改动点有以下三个:
1.不需要实现IFieldWiring接口
2.删除annotationClass方法
3.将wiring方法修改为static方法
具体代码如下:
 

  1. import java.lang.reflect.Field;  
  2.  
  3. public class DataSourceStaticWiring {  
  4.  
  5.     public static void wiring(Object object, Field field) {  
  6.         Object fieldObj = ReflectUtils.getFieldValue(object, field.getName());  
  7.         if (fieldObj != null) {  
  8.             return;  
  9.         }  
  10.         DataSource annotation = field.getAnnotation(DataSource.class);  
  11.         String type = annotation.type();  
  12.         String sqlMap = annotation.sqlMap();  
  13.         // 这里可以用缓存来实现,不用每次都去创建新的SqlMapClient对象  
  14.         SqlMapClient sqlMapImpl = new SqlMapClient(sqlMap, type);  
  15.         ReflectUtils.setFieldValue(object, field.getName(), SqlMapClient.class, sqlMapImpl);  
  16.     }  


注:SqlMapClient、ReflectUtils实现在上一篇 利用自定义Java注解实现资源注入 中。

代码已准备就绪,接下来是配置Spring:applicationContext.xml
 

  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  3.     xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 
  4.     xmlns:context="http://www.springframework.org/schema/context" 
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans   
  6.                         http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
  7.                         http://www.springframework.org/schema/aop   
  8.                         http://www.springframework.org/schema/aop/spring-aop-2.5.xsd  
  9.                         http://www.springframework.org/schema/tx   
  10.                         http://www.springframework.org/schema/tx/spring-tx-2.5.xsd  
  11.                         http://www.springframework.org/schema/context  
  12.            http://www.springframework.org/schema/context/spring-context-2.5.xsd"  
  13.     default-lazy-init="true"> 
  14.       
  15.     <!-- 自定义的BeanProcessor --> 
  16.     <bean class="com.annotation.DataSourceBeanProcessor" /> 
  17.     <context:component-scan base-package="com.annotation" /> 
  18.  
  19.     <!-- 测试用bean --> 
  20.     <bean id="myService" class="com.annotation.MyService" destroy-method="close"> 
  21.     </bean> 
  22. </beans> 


测试代码其实已经在前面列出来了。SpringWiringTest.java
 

  1. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  2.  
  3. import com.annotation.MyService;  
  4.  
  5. public class SpringWiringTest {  
  6.     public static void main(String args[]) {  
  7.         ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("com/spring/applicationContext.xml");  
  8.         MyService b = (MyService)ctx.getBean("myService");  
  9.         System.out.println(b.selectForObjectFromB(""null));  
  10.         System.out.println(b.selectForObjectFromA(""null));  
  11.     }  


执行结果:
 

SqlMapClient[sqlMap=com/annotation/sql-map-config-B.xml,type=B]
SqlMapClient[sqlMap
=com/annotation/sql-map-config-A.xml,type=A]


由结果可见,我们利用Spring完成了对DataSource资源的注入了。

在这里如果还想扩展的话,就需要新建类假设为InParamBeanProcessor,实现BeanPostProcessor、PriorityOrdered接口,然后实现其中的方法,对资源进行注入,这里就是扩展Spring了,与本篇介绍的方法相同。

注:以上代码重在演示,其实这个需求可以在Spring中管理两个不同的SqlMapClient对象,然后通过Spring的自动注入实现。