1. 程式人生 > >spring中註解的實現原理

spring中註解的實現原理

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

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

1、定義註解

Java程式碼 複製程式碼 收藏程式碼
1.package com.yt.annotation; 
2. 
3.import java.lang.annotation.ElementType; 
4.import java.lang.annotation.Retention; 
5.import java.lang.annotation.RetentionPolicy; 
6.import java.lang.annotation.Target; 
7. 
8./**
9. * @Description:定義註解
10. * @ClassName: ZxfResource
11. * @Project: spring-aop
12. * @Author: zxf
13. * @Date: 2011-6-7
14. */ 
15.// 在執行時執行 

[email protected](RetentionPolicy.RUNTIME
17.// 註解適用地方(欄位和方法) 
[email protected]({ ElementType.FIELD, ElementType.METHOD }) 
19.public @interface ZxfResource { 
20. 
21.    //註解的name屬性 
22.    public String name() default ""; 
23.} 


 2、帶有註解的服務類

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


 3、要注入的DAO

Java程式碼 複製程式碼 收藏程式碼
1.package com.yt.annotation; 
2. 
3./**
4. * @Description: 要注入的DAo類
5. * @ClassName: UserDaoImpl
6. * @Project: spring-aop
7. * @Author: zxf
8. * @Date: 2011-6-7
9. */ 
10.public class UserDaoImpl { 
11.     
12.    String name ; 
13.     
14.    public void show(){ 
15.        System.out.println("這裡是dao方法........"); 
16.    } 
17.} 


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. 
3.import java.beans.Introspector; 
4.import java.beans.PropertyDescriptor; 
5.import java.lang.reflect.Field; 
6.import java.lang.reflect.Method; 
7.import java.util.ArrayList; 
8.import java.util.HashMap; 
9.import java.util.Iterator; 
10.import java.util.List; 
11.import java.util.Map; 
12.import org.apache.log4j.Logger; 
13.import org.dom4j.Document; 
14.import org.dom4j.DocumentException; 
15.import org.dom4j.Element; 
16.import org.dom4j.io.SAXReader; 
17. 
18./**
19. * @Description: spring中的註解原理
20. * @ClassName: ClassPathXMLApplicationContext
21. * @Project: spring-aop
22. * @Author: zxf
23. * @Date: 2011-6-3
24. */ 
25.public class ClassPathXMLApplicationContext { 
26. 
27.    Logger log = Logger.getLogger(ClassPathXMLApplicationContext.class); 
28. 
29.    List<BeanDefine> beanList = new ArrayList<BeanDefine>(); 
30.    Map<String, Object> sigletions = new HashMap<String, Object>(); 
31. 
32.    public ClassPathXMLApplicationContext(String fileName) { 
33.        //讀取配置檔案中管理的bean 
34.        this.readXML(fileName); 
35.        //例項化bean 
36.        this.instancesBean(); 
37.        //註解處理器 
38.        this.annotationInject(); 
39.    } 
40. 
41.    /**
42.     * 讀取Bean配置檔案
43.     * @param fileName
44.     * @return
45.     */ 
46.    @SuppressWarnings("unchecked") 
47.    public void readXML(String fileName) { 
48.        Document document = null; 
49.        SAXReader saxReader = new SAXReader(); 
50.        try { 
51.            ClassLoader classLoader =  
52.                Thread.currentThread().getContextClassLoader(); 
53.            document = saxReader.read(classLoader.getResourceAsStream(fileName)); 
54.            Element beans = document.getRootElement(); 
55.            for (Iterator<Element> beansList = beans.elementIterator();  
56.                beansList.hasNext();) { 
57.                Element element = beansList.next(); 
58.                BeanDefine bean = new BeanDefine( 
59.                        element.attributeValue("id"), 
60.                        element.attributeValue("class")); 
61.                beanList.add(bean); 
62.            } 
63.        } catch (DocumentException e) { 
64.            log.info("讀取配置檔案出錯...."); 
65.        } 
66.    } 
67.     
68.    /**
69.     * 例項化Bean
70.     */ 
71.    public void instancesBean() { 
72.        for (BeanDefine bean : beanList) { 
73.            try { 
74.                sigletions.put(bean.getId(),  
75.                        Class.forName(bean.getClassName()).newInstance()); 
76.            } catch (Exception e) { 
77.                log.info("例項化Bean出錯..."); 
78.            } 
79.        } 
80.    } 
81.     
82.    /**
83.     * 註解處理器
84.     * 如果註解ZxfResource配置了name屬性,則根據name所指定的名稱獲取要注入的例項引用,
85.     * 如果註解ZxfResource;沒有配置name屬性,則根據屬性所屬型別來掃描配置檔案獲取要
86.     * 注入的例項引用
87.     * 
88.     */ 
89.    public void annotationInject(){ 
90.        for(String beanName:sigletions.keySet()){ 
91.            Object bean = sigletions.get(beanName); 
92.            if(bean!=null){ 
93.                this.propertyAnnotation(bean); 
94.                this.fieldAnnotation(bean); 
95.            } 
96.        } 
97.    } 
98.     
99.    /**
100.     * 處理在set方法加入的註解
101.     * @param bean 處理的bean
102.     */ 
103.    public void propertyAnnotation(Object bean){ 
104.        try { 
105.            //獲取其屬性的描述 
106.            PropertyDescriptor[] ps =  
107.                Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors(); 
108.            for(PropertyDescriptor proderdesc : ps){ 
109.                //獲取所有set方法 
110.                Method setter = proderdesc.getWriteMethod(); 
111.                //判斷set方法是否定義了註解 
112.                if(setter!=null && setter.isAnnotationPresent(ZxfResource.class)){ 
113.                    //獲取當前註解,並判斷name屬性是否為空 
114.                    ZxfResource resource = setter.getAnnotation(ZxfResource.class); 
115.                    String name =""; 
116.                    Object value = null; 
117.                    if(resource.name()!=null&&!"".equals(resource.name())){ 
118.                        //獲取註解的name屬性的內容 
119.                        name = resource.name(); 
120.                        value = sigletions.get(name); 
121.                    }else{ //如果當前註解沒有指定name屬性,則根據型別進行匹配 
122.                        for(String key : sigletions.keySet()){ 
123.                            //判斷當前屬性所屬的型別是否在配置檔案中存在 
124.                            if(proderdesc.getPropertyType().isAssignableFrom(sigletions.get(key).getClass())){ 
125.                                //獲取型別匹配的例項物件 
126.                                value = sigletions.get(key); 
127.                                break; 
128.                            } 
129.                        } 
130.                    } 
131.                    //允許訪問private方法 
132.                    setter.setAccessible(true); 
133.                    //把引用物件注入屬性 
134.                    setter.invoke(bean, value);  
135.                } 
136.            } 
137.        } catch (Exception e) { 
138.            log.info("set方法註解解析異常.........."); 
139.        } 
140.    } 
141.     
142.    /**
143.     * 處理在欄位上的註解
144.     * @param bean 處理的bean
145.     */ 
146.    public void fieldAnnotation(Object bean){ 
147.        try { 
148.            //獲取其全部的欄位描述 
149.            Field[] fields = bean.getClass().getFields(); 
150.            for(Field f : fields){ 
151.                if(f!=null && f.isAnnotationPresent(ZxfResource.class)){ 
152.                    ZxfResource resource = f.getAnnotation(ZxfResource.class); 
153.                    String name =""; 
154.                    Object value = null; 
155.                    if(resource.name()!=null&&!"".equals(resource.name())){ 
156.                        name = resource.name(); 
157.                        value = sigletions.get(name); 
158.                    }else{ 
159.                        for(String key : sigletions.keySet()){ 
160.                            //判斷當前屬性所屬的型別是否在配置檔案中存在 
161.                            if(f.getType().isAssignableFrom(sigletions.get(key).getClass())){ 
162.                                //獲取型別匹配的例項物件 
163.                                value = sigletions.get(key); 
164.                                break; 
165.                            } 
166.                        } 
167.                    } 
168.                    //允許訪問private欄位 
169.                    f.setAccessible(true); 
170.                    //把引用物件注入屬性 
171.                    f.set(bean, value); 
172.                } 
173.            } 
174.        } catch (Exception e) { 
175.            log.info("欄位註解解析異常.........."); 
176.        } 
177.    } 
178.     
179.    /**
180.     * 獲取Map中的對應的bean例項
181.     * @param beanId
182.     * @return
183.     */ 
184.    public Object getBean(String beanId) { 
185.        return sigletions.get(beanId); 
186.    } 
187. 
188. 
189.    public static void main(String[] args) { 
190.        ClassPathXMLApplicationContext path = new ClassPathXMLApplicationContext( 
191.                "configAnnotation.xml"); 
192.        UserServiceImpl userService =(UserServiceImpl)path.getBean("userService"); 
193.        userService.show(); 
194.    } 
195.} 

@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屬性,就只能按名稱裝配了。