深入探索spring技术内幕: 剖析@Resource注解实现原理与注解注入

一、@Resource注解原理

@Resource可以标注在字段或属性的setter方法上

1.  如果指定了name属性, 那么就按name属性的名称装配; 

2. 如果没有指定name属性, 那就按照默认的名称查找依赖对象;

3. 如果按默认名称查找不到依赖对象, 那么@Resource注解就会回退到按类型装配;


① 先写一个自己的@MyResource:

[java]  view plain  copy
  1. import java.lang.annotation.Retention;  
  2. import java.lang.annotation.RetentionPolicy;  
  3. import java.lang.annotation.Target;  
  4. import java.lang.annotation.ElementType;  
  5.   
  6. @Retention(RetentionPolicy.RUNTIME) // 指定注解保留的范围 (运行期)  
  7. @Target({ ElementType.FIELD, ElementType.METHOD }) // 允许注解标注的位置 (属性, 方法)  
  8. public @interface MyResource {  
  9.     public String name() default ""// 提供name属性  
  10. }  
② Spring Bean Factory: ClassPathXMLApplicationContext

[java]  view plain  copy
  1. import java.beans.Introspector;  
  2. import java.beans.PropertyDescriptor;  
  3. import java.lang.reflect.Field;  
  4. import java.lang.reflect.Method;  
  5. import java.net.URL;  
  6. import java.util.ArrayList;  
  7. import java.util.HashMap;  
  8. import java.util.List;  
  9. import java.util.Map;  
  10. import org.apache.commons.beanutils.ConvertUtils;  
  11. import org.dom4j.Document;  
  12. import org.dom4j.Element;  
  13. import org.dom4j.XPath;  
  14. import org.dom4j.io.SAXReader;  
  15.   
  16. /** 
  17.  * Spring Bean Factory 
  18.  */  
  19. public class ClassPathXMLApplicationContext {  
  20.     private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();  
  21.     private Map<String, Object> sigletons = new HashMap<String, Object>();  
  22.   
  23.     public ClassPathXMLApplicationContext(String filename) {  
  24.         this.readXML(filename);  
  25.         this.instanceBeans();  
  26.         this.annotationInject();  
  27.         this.injectObject();  
  28.     }  
  29.   
  30.     /** 
  31.      * 通过注解实现注入依赖对象 
  32.      */  
  33.     private void annotationInject() {  
  34.         for (String beanName : sigletons.keySet()) { // 循环所有的Bean对象  
  35.             Object bean = sigletons.get(beanName);  
  36.             if (bean != null) {  
  37.                 try {  
  38.                     // 查找属性的setter上是否有注解  
  39.                     PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();   
  40.                     for (PropertyDescriptor properdesc : ps) { // 循环所有属性  
  41.                         Method setter = properdesc.getWriteMethod();// 获取属性的setter方法  
  42.                         if (setter != null && setter.isAnnotationPresent(MyResource.class)) { // 判断MyResource注解是否存在  
  43.                             MyResource resource = setter.getAnnotation(MyResource.class);  
  44.                             Object injectBean = null;  
  45.                             if (resource.name() != null && !"".equals(resource.name())) {  
  46.                                 injectBean = sigletons.get(resource.name()); // 通过MyResource注解的name属性获取Bean  
  47.                             } else {   
  48.                                 injectBean = sigletons.get(properdesc.getName());  
  49.                                 if (injectBean == null) { // 没有指定name属性, 根据属性名称进行寻找  
  50.                                     for (String key : sigletons.keySet()) {  
  51.                                         // 根据属性类型进行寻找  
  52.                                         if (properdesc.getPropertyType().isAssignableFrom(sigletons.get(key).getClass())) {   
  53.                                             injectBean = sigletons.get(key);  
  54.                                             break;  
  55.                                         }  
  56.                                     }  
  57.                                 }  
  58.                             }  
  59.                             setter.setAccessible(true);   
  60.                             setter.invoke(bean, injectBean);// 把引用对象注入到属性  
  61.                         }  
  62.                     }  
  63.                       
  64.                     // 查找字段上是否有注解  
  65.                     Field[] fields = bean.getClass().getDeclaredFields(); // 取得声明的所有字段  
  66.                     for (Field field : fields) {  
  67.                         if (field.isAnnotationPresent(MyResource.class)) { // 判断字段上是否存在MyResource注解  
  68.                             MyResource resource = field.getAnnotation(MyResource.class);  
  69.                             Object value = null;  
  70.                             if (resource.name() != null && !"".equals(resource.name())) { // 判断是否指定name属性  
  71.                                 value = sigletons.get(resource.name());  
  72.                             } else {  
  73.                                 value = sigletons.get(field.getName()); // 没有指定name属性,那么根据字段名称寻找  
  74.                                 if (value == null) {  
  75.                                     for (String key : sigletons.keySet()) {  
  76.                                         // 根据字段类型进行寻找  
  77.                                         if (field.getType().isAssignableFrom(sigletons.get(key).getClass())) {   
  78.                                             value = sigletons.get(key);  
  79.                                             break;  
  80.                                         }  
  81.                                     }  
  82.                                 }  
  83.                             }  
  84.                             field.setAccessible(true);// 允许访问private字段  
  85.                             field.set(bean, value);  
  86.                         }  
  87.                     }  
  88.                 } catch (Exception e) {  
  89.                     e.printStackTrace();  
  90.                 }  
  91.             }  
  92.         }  
  93.     }  
  94.   
  95.     /** 
  96.      * 为bean对象的属性注入值 
  97.      */  
  98.     private void injectObject() {  
  99.         for (BeanDefinition beanDefinition : beanDefines) {  
  100.             Object bean = sigletons.get(beanDefinition.getId());  
  101.             if (bean != null) {  
  102.                 try {  
  103.                     PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();  
  104.                     for (PropertyDefinition propertyDefinition : beanDefinition.getPropertys()) {  
  105.                         for (PropertyDescriptor properdesc : ps) {  
  106.                             if (propertyDefinition.getName().equals(properdesc.getName())) {  
  107.                                 Method setter = properdesc.getWriteMethod(); // 获取属性的setter方法  
  108.                                 if (setter != null) {  
  109.                                     Object injectBean = null;  
  110.                                     if (propertyDefinition.getRef() != null && !"".equals(propertyDefinition.getRef().trim())) {  
  111.                                         injectBean = sigletons.get(propertyDefinition.getRef());  
  112.                                     } else {  
  113.                                         injectBean = ConvertUtils.convert(propertyDefinition.getValue(), properdesc.getPropertyType());  
  114.                                     }  
  115.                                     setter.setAccessible(true); // private method  
  116.                                     setter.invoke(bean, injectBean); // 把引用对象注入到属性  
  117.                                 }  
  118.                                 break;  
  119.                             }  
  120.                         }  
  121.                     }  
  122.                 } catch (Exception e) {  
  123.                     e.printStackTrace();  
  124.                 }  
  125.             }  
  126.         }  
  127.     }  
  128.   
  129.     /** 
  130.      * 完成bean的实例化 
  131.      */  
  132.     private void instanceBeans() {  
  133.         for (BeanDefinition beanDefinition : beanDefines) {  
  134.             try {  
  135.                 if (beanDefinition.getClassName() != null && !"".equals(beanDefinition.getClassName().trim()))  
  136.                     sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance());  
  137.             } catch (Exception e) {  
  138.                 e.printStackTrace();  
  139.             }  
  140.         }  
  141.   
  142.     }  
  143.   
  144.     /** 
  145.      * 读取xml配置文件 
  146.      *  
  147.      * @param filename 
  148.      */  
  149.     private void readXML(String filename) {  
  150.         SAXReader saxReader = new SAXReader();  
  151.         Document document = null;  
  152.         try {  
  153.             URL xmlpath = this.getClass().getClassLoader().getResource(filename);  
  154.             document = saxReader.read(xmlpath);  
  155.             Map<String, String> nsMap = new HashMap<String, String>();  
  156.             nsMap.put("ns""http://www.springframework.org/schema/beans");// 加入命名空间  
  157.             XPath xsub = document.createXPath("//ns:beans/ns:bean");// 创建beans/bean查询路径  
  158.             xsub.setNamespaceURIs(nsMap);// 设置命名空间  
  159.             List<Element> beans = xsub.selectNodes(document);// 获取文档下所有bean节点  
  160.             for (Element element : beans) {  
  161.                 String id = element.attributeValue("id");// 获取id属性值  
  162.                 String clazz = element.attributeValue("class"); // 获取class属性值  
  163.                 BeanDefinition beanDefine = new BeanDefinition(id, clazz);  
  164.                 XPath propertysub = element.createXPath("ns:property");  
  165.                 propertysub.setNamespaceURIs(nsMap);// 设置命名空间  
  166.                 List<Element> propertys = propertysub.selectNodes(element);  
  167.                 for (Element property : propertys) {  
  168.                     String propertyName = property.attributeValue("name");  
  169.                     String propertyRef = property.attributeValue("ref");  
  170.                     String propertyValue = property.attributeValue("value");  
  171.                     PropertyDefinition propertyDefinition = new PropertyDefinition(propertyName, propertyRef, propertyValue);  
  172.                     beanDefine.getPropertys().add(propertyDefinition);  
  173.                 }  
  174.                 beanDefines.add(beanDefine);  
  175.             }  
  176.         } catch (Exception e) {  
  177.             e.printStackTrace();  
  178.         }  
  179.     }  
  180.   
  181.     /** 
  182.      * 获取bean实例 
  183.      *  
  184.      * @param beanName 
  185.      * @return 
  186.      */  
  187.     public Object getBean(String beanName) {  
  188.         return this.sigletons.get(beanName);  
  189.     }  
  190. }  

③ beans.xml

扫描二维码关注公众号,回复: 1682488 查看本文章

[html]  view plain  copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  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/context  
  8.            http://www.springframework.org/schema/context/spring-context-2.5.xsd">  
  9.     <context:annotation-config />  
  10.     <bean id="personDao" class="com.zdp.dao.impl.PersonDaoImpl" />  
  11.     <bean id="personService" class="com.zdp.service.impl.PersonServiceImpl" />  
  12. </beans>  
④ PersonServiceImpl

[java]  view plain  copy
  1. import com.zdp.dao.PersonDao;  
  2. import com.zdp.myspring.MyResource;  
  3. import com.zdp.service.PersonService;  
  4.   
  5. public class PersonServiceImpl implements PersonService {  
  6.     private PersonDao personDao;  
  7.       
  8.     @MyResource(name="personDao")   
  9.     public void setPersonDao(PersonDao personDao) {  
  10.         this.personDao = personDao;  
  11.     }  
  12.   
  13.     public void save() {  
  14.         personDao.save();  
  15.     }  
  16. }  
⑤ 测试一下

[java]  view plain  copy
  1. import org.junit.Test;  
  2. import com.zdp.service.PersonService;  
  3. import com.zdp.myspring.ClassPathXMLApplicationContext;  
  4. public class PersonServiceImplTest {  
  5.     @Test  
  6.     public void testSave() {  
  7.         ClassPathXMLApplicationContext ctx = new ClassPathXMLApplicationContext("beans.xml");  
  8.         PersonService personService = (PersonService)ctx.getBean("personService");  
  9.         personService.save();  
  10.     }  
  11. }  

二、spring注解注入

① 引入common-annotations.jar

② 在xml中做如下配置:

[html]  view plain  copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  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/context  
  8.            http://www.springframework.org/schema/context/spring-context-2.5.xsd">  
  9.     <context:annotation-config />  
  10. </beans>  

③ 在Java代码中使用@Autowired或@Resource注解方式进行装配

二者区别: @Autowired默认按类型装配, @Resource默认按名称装配, 当找不到与名称匹配的Bean才会按类型匹配.

[java]  view plain  copy
  1. @Resource // 配置在属性上  
  2. private PersonDao personDao;  

[java]  view plain  copy
  1. @Resource(name="personDao"// 名称通过@Resource的name属性指定  
  2. private PersonDao personDao;  


[java]  view plain  copy
  1. @Resource // 配置在setter方法上  
  2. public void setPersonDao(PersonDao personDao) {  
  3.     this.personDao = personDao;   
  4. }  


@Autowired注解是按类型装配依赖对象, 默认情况下它要求依赖对象必须存在, 

如果允许null值, 可以设置required=false

如果想使用按名称装配, 可以结合@Qualifier注解一起使用

[java]  view plain  copy
  1. @Autowired @Qualifier("personDao")  
  2. private PersonDao personDao  


三、spring自动扫描和管理Bean

前面的例子都是使用xml的bean定义来配置组件, 在一个稍大的项目中, 通常会有上百个组件, 如果这些组件都采用xml的bean定义来配置, 显然会增加配置文件的体积, 查找及维护起来也不太方便. 


spring2.5为我们引入了组件自动扫描机制, 它可以在类路径下寻找标注了@Component、@Controller、@Service、@Reponsitory注解的类, 并把这些类纳入进spring容器中管理. 它的作用和在xml中使用bean节点配置组件是一样的.

① beans.xml

[html]  view plain  copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  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/context  
  8.            http://www.springframework.org/schema/context/spring-context-2.5.xsd">  
  9.              
  10.     <context:component-scan base-package="com.zdp"/>   
  11.     <!-- base-package为需要扫描的包(含子包) -->  
  12. </beans>  
② PersonServiceImpl
[java]  view plain  copy
  1. @Service("personService")   
  2. @Scope("singleton")  
  3. public class PersonServiceImpl implements PersonService {  
  4.     private PersonDao personDao;  
  5.       
  6.     @Resource(name="personDao")   
  7.     public void setPersonDao(PersonDao personDao) {  
  8.         this.personDao = personDao;  
  9.     }  
  10.       
  11.     @PostConstruct  
  12.     public void init(){  
  13.         System.out.println("init..");  
  14.     }  
  15.       
  16.     @PreDestroy  
  17.     public void destory(){  
  18.         System.out.println("destory..");  
  19.     }  
  20.     public void save() {  
  21.         personDao.save();  
  22.     }  
  23. }  
@Controller通常用于标注控制层组件(如struts中的action);

@Service通常用于标注业务层组件;

@Repository通常用于标注数据访问组件, 即DAO组件;

@Component泛指组件, 当组件不好归类的时候, 我们可以使用这个注解进行标注;


版权声明: https://blog.csdn.net/zdp072/article/details/25558563

猜你喜欢

转载自blog.csdn.net/l18848956739/article/details/79868616