1. 程式人生 > >spring中註解處理框架解析----原始碼實現

spring中註解處理框架解析----原始碼實現

@Autowired和@Resource的區別:

在Java中使用@Autowired和@Resource註解進行裝配,這兩個註解分別是:
1、@Autowired按照預設型別(類名稱)裝配依賴物件,預設情況下它要求依賴物件必須存在,如果允許為null,可以設定它的required屬性為false
如果我們按名稱裝配,可以結合@Qualifie註解一起使用。
如:
@Autowired @qualifie("personDaoBean")
private PersonDaoBean personDaoBean;

@Resource預設按照名稱(name="test")進行裝配,名稱可以通過@resource的name屬性設定,當找不到與名稱匹配的bean才會按型別裝配

注意:如果沒有指定name屬性,並且安裝預設的名稱依然找不到依賴物件時,@Resource會回退到按型別裝配。但一旦指定了name屬性,就只能按名稱裝配了。

下面的示例來簡單的講述spring註解原理:

本例實現了在set方法上和在欄位屬性上註解的處理解析。

1、定義註解

Java程式碼  收藏程式碼
  1. package com.yt.annotation;  
  2. import java.lang.annotation.ElementType;  
  3. import java.lang.annotation.Retention;  
  4. import java.lang.annotation.RetentionPolicy;  
  5. import java.lang.annotation.Target;  
  6. /** 
  7.  * @Description:定義註解 
  8.  * @ClassName: ZxfResource 
  9.  * @Project: spring-aop 
  10.  * @Author: zxf 
  11.  * @Date: 2011-6-7 
  12.  */  
  13. // 在執行時執行  
  14. @Retention(RetentionPolicy.RUNTIME)  
  15. // 註解適用地方(欄位和方法)  
  16. @Target({ ElementType.FIELD, ElementType.METHOD })  
  17. public @interface ZxfResource {  
  18.     //註解的name屬性  
  19.     public String name() default "";  
  20. }  

 2、帶有註解的服務類

Java程式碼  收藏程式碼
  1. package com.yt.annotation;  
  2. /** 
  3.  * @Description: 帶有註解的服務 
  4.  * @ClassName: UserDaoImpl 
  5.  * @Project: spring-aop 
  6.  * @Author: zxf 
  7.  * @Date: 2011-6-7 
  8.  */  
  9. public class UserServiceImpl {  
  10.     public UserDaoImpl userDao;  
  11.     public User1DaoImpl user1Dao;  
  12.     // 欄位上的註解,可以配置name屬性  
  13.     @ZxfResource  
  14.     public User2DaoImpl user2Dao;  
  15.     // set方法上的註解,帶有name屬性  
  16.     @ZxfResource(name = "userDao")  
  17.     public void setUserDao(UserDaoImpl userDao) {  
  18.         this.userDao = userDao;  
  19.     }  
  20.     // set方法上的註解,沒有配置name屬性  
  21.     @ZxfResource  
  22.     public void setUser1Dao(User1DaoImpl user1Dao) {  
  23.         this.user1Dao = user1Dao;  
  24.     }  
  25.     public void show() {  
  26.         userDao.show();  
  27.         user1Dao.show1();  
  28.         user2Dao.show2();  
  29.         System.out.println("這裡是Service方法........");  
  30.     }  
  31. }  

 3、要注入的DAO

Java程式碼  收藏程式碼
  1. package com.yt.annotation;  
  2. /** 
  3.  * @Description: 要注入的DAo類 
  4.  * @ClassName: UserDaoImpl 
  5.  * @Project: spring-aop 
  6.  * @Author: zxf 
  7.  * @Date: 2011-6-7 
  8.  */  
  9. public class UserDaoImpl {  
  10.     String name ;  
  11.     public void show(){  
  12.         System.out.println("這裡是dao方法........");  
  13.     }  
  14. }  
Xml程式碼  收藏程式碼
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans>  
  3.     <bean id = "userDao" class="com.yt.annotation.UserDaoImpl" />  
  4.     <bean id = "user1Dao" class="com.yt.annotation.User1DaoImpl" />  
  5.     <bean id = "user2Dao" class="com.yt.annotation.User2DaoImpl" />  
  6.     <bean id = "userService" class = "com.yt.annotation.UserServiceImpl" />  
  7. </beans>  

 4、註解處理器

Java程式碼  收藏程式碼
  1. package com.yt.annotation;  
  2. import java.beans.Introspector;  
  3. import java.beans.PropertyDescriptor;  
  4. import java.lang.reflect.Field;  
  5. import java.lang.reflect.Method;  
  6. import java.util.ArrayList;  
  7. import java.util.HashMap;  
  8. import java.util.Iterator;  
  9. import java.util.List;  
  10. import java.util.Map;  
  11. import org.apache.log4j.Logger;  
  12. import org.dom4j.Document;  
  13. import org.dom4j.DocumentException;  
  14. import org.dom4j.Element;  
  15. import org.dom4j.io.SAXReader;  
  16. /** 
  17.  * @Description: spring中的註解原理 
  18.  * @ClassName: ClassPathXMLApplicationContext 
  19.  * @Project: spring-aop 
  20.  * @Author: zxf 
  21.  * @Date: 2011-6-3 
  22.  */  
  23. public class ClassPathXMLApplicationContext {  
  24.     Logger log = Logger.getLogger(ClassPathXMLApplicationContext.class);  
  25.     List<BeanDefine> beanList = new ArrayList<BeanDefine>();  
  26.     Map<String, Object> sigletions = new HashMap<String, Object>();  
  27.     public ClassPathXMLApplicationContext(String fileName) {  
  28.         //讀取配置檔案中管理的bean  
  29.         this.readXML(fileName);  
  30.         //例項化bean  
  31.         this.instancesBean();  
  32.         //註解處理器  
  33.         this.annotationInject();  
  34.     }  
  35.     /** 
  36.      * 讀取Bean配置檔案 
  37.      * @param fileName 
  38.      * @return 
  39.      */  
  40.     @SuppressWarnings("unchecked")  
  41.     public void readXML(String fileName) {  
  42.         Document document = null;  
  43.         SAXReader saxReader = new SAXReader();  
  44.         try {  
  45.             ClassLoader classLoader =   
  46.                 Thread.currentThread().getContextClassLoader();  
  47.             document = saxReader.read(classLoader.getResourceAsStream(fileName));  
  48.             Element beans = document.getRootElement();  
  49.             for (Iterator<Element> beansList = beans.elementIterator();   
  50.                 beansList.hasNext();) {  
  51.                 Element element = beansList.next();  
  52.                 BeanDefine bean = new BeanDefine(  
  53.                         element.attributeValue("id"),  
  54.                         element.attributeValue("class"));  
  55.                 beanList.add(bean);  
  56.             }  
  57.         } catch (DocumentException e) {  
  58.             log.info("讀取配置檔案出錯....");  
  59.         }  
  60.     }  
  61.     /** 
  62.      * 例項化Bean 
  63.      */  
  64.     public void instancesBean() {  
  65.         for (BeanDefine bean : beanList) {  
  66.             try {  
  67.                 sigletions.put(bean.getId(),   
  68.                         Class.forName(bean.getClassName()).newInstance());  
  69.             } catch (Exception e) {  
  70.                 log.info("例項化Bean出錯...");  
  71.             }  
  72.         }  
  73.     }  
  74.     /** 
  75.      * 註解處理器 
  76.      * 如果註解ZxfResource配置了name屬性,則根據name所指定的名稱獲取要注入的例項引用, 
  77.      * 如果註解ZxfResource;沒有配置name屬性,則根據屬性所屬型別來掃描配置檔案獲取要 
  78.      * 注入的例項引用 
  79.      *  
  80.      */  
  81.     public void annotationInject(){  
  82.         for(String beanName:sigletions.keySet()){  
  83.             Object bean = sigletions.get(beanName);  
  84.             if(bean!=null){  
  85.                 this.propertyAnnotation(bean);  
  86.                 this.fieldAnnotation(bean);  
  87.             }  
  88.         }  
  89.     }  
  90.     /** 
  91.      * 處理在set方法加入的註解 
  92.      * @param bean 處理的bean 
  93.      */  
  94.     public void propertyAnnotation(Object bean){  
  95.         try {  
  96.             //獲取其屬性的描述  
  97.             PropertyDescriptor[] ps =   
  98.                 Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();  
  99.             for(PropertyDescriptor proderdesc : ps){  
  100.                 //獲取所有set方法  
  101.                 Method setter = proderdesc.getWriteMethod();  
  102.                 //判斷set方法是否定義了註解  
  103.                 if(setter!=null && setter.isAnnotationPresent(ZxfResource.class)){  
  104.                     //獲取當前註解,並判斷name屬性是否為空  
  105.                     ZxfResource resource = setter.getAnnotation(ZxfResource.class);  
  106.                     String name ="";  
  107.                     Object value = null;  
  108.                     if(resource.name()!=null&&!"".equals(resource.name())){  
  109.                         //獲取註解的name屬性的內容  
  110.                         name = resource.name();  
  111.                         value = sigletions.get(name);  
  112.                     }else//如果當前註解沒有指定name屬性,則根據型別進行匹配  
  113.                         for(String key : sigletions.keySet()){  
  114.                             //判斷當前屬性所屬的型別是否在配置檔案中存在  
  115. 相關推薦

    no