一、@Resource注解原理
@Resource可以标注在字段或属性的setter方法上
1. 如果指定了name属性, 那么就按name属性的名称装配;
2. 如果没有指定name属性, 那就按照默认的名称查找依赖对象;
3. 如果按默认名称查找不到依赖对象, 那么@Resource注解就会回退到按类型装配;
① 先写一个自己的@MyResource:
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
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
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泛指组件, 当组件不好归类的时候, 我们可以使用这个注解进行标注;