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.// 在執行時執行
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屬性,就只能按名稱裝配了。