一、@Resource注解原理

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

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

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

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


① 先写一个自己的@MyResource:

[java] 

   
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] 

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. // 获取属性的setter方法  
42. if (setter != null && setter.isAnnotationPresent(MyResource.class)) { // 判断MyResource注解是否存在  
43. class);  
44. null;  
45. if (resource.name() != null && !"".equals(resource.name())) {  
46. // 通过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. true);   
60. // 把引用对象注入到属性  
61.                         }  
62.                     }  
63.                       
64. // 查找字段上是否有注解  
65. // 取得声明的所有字段  
66. for (Field field : fields) {  
67. if (field.isAnnotationPresent(MyResource.class)) { // 判断字段上是否存在MyResource注解  
68. class);  
69. null;  
70. if (resource.name() != null && !"".equals(resource.name())) { // 判断是否指定name属性  
71.                                 value = sigletons.get(resource.name());  
72. else {  
73. // 没有指定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. 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. // 获取属性的setter方法  
108. if (setter != null) {  
109. 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. true); // private method  
116. // 把引用对象注入到属性  
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. new SAXReader();  
151. null;  
152. try {  
153. this.getClass().getClassLoader().getResource(filename);  
154.             document = saxReader.read(xmlpath);  
155. new HashMap<String, String>();  
156. "ns", "http://www.springframework.org/schema/beans");// 加入命名空间  
157. "//ns:beans/ns:bean");// 创建beans/bean查询路径  
158. // 设置命名空间  
159. // 获取文档下所有bean节点  
160. for (Element element : beans) {  
161. "id");// 获取id属性值  
162. "class"); // 获取class属性值  
163. new BeanDefinition(id, clazz);  
164. "ns:property");  
165. // 设置命名空间  
166.                 List<Element> propertys = propertysub.selectNodes(element);  
167. for (Element property : propertys) {  
168. "name");  
169. "ref");  
170. "value");  
171. 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


[html] 

   
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. >  
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]

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]

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. new ClassPathXMLApplicationContext("beans.xml");  
8. "personService");  
9.         personService.save();  
10.     }  
11. }


二、spring注解注入

① 引入common-annotations.jar

② 在xml中做如下配置:


[html]

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. >  
9. <context:annotation-config />  
10. </beans>

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

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

[java]

1. @Resource // 配置在属性上  
2. private PersonDao personDao;


[java]

1. @Resource(name="personDao") // 名称通过@Resource的name属性指定  
2. private PersonDao personDao;


[java]

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


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

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

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



[java]

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]

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. >  
9.              
10. <context:component-scan base-package="com.zdp"/>   
11. <!-- base-package为需要扫描的包(含子包) -->  
12. </beans>


② PersonServiceImpl

[java]

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. "init..");  
14.     }  
15.       
16. @PreDestroy  
17. public void destory(){  
18. "destory..");  
19.     }  
20. public void save() {  
21.         personDao.save();  
22.     }  
23. }

@Controller通常用于标注控制层组件(如struts中的action);

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

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

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