最近使用Spring里面的依赖注入,比如StudentServiceImple2.java代码:
package di.service.imple; import com.mengya.spring.annotation.MyResource; import di.dao.StudentDao; import di.service.StudentService; public class StudentServiceImple2 implements StudentService { @MyResource private StudentDao stuDao; public void save() { stuDao.add(); } }
就是向属性stuDao注入一个StudengDao对象,那么这是怎么实现的哪?如果想要彻底了解它,需要提前知道两个知识点,反射和注解:http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html
据我的理解,他的过程如下:
那么让我们根据事例来逐条分析。
这需要三个文件来实现:bean3.xml、MySpringAnnotationTest.java、MengyaClassPathXMLApplicationContext.java
这就是一个普普通通的xml文件,里面包含了stuDao和stuService两个Bean。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="stuDao" class="di.dao.imple.StudentDaoImple"></bean> <bean id="stuService" class="di.service.imple.StudentServiceImple2"></bean> </beans>
这个是解析XML的一个类,没啥说的
package com.test; import com.mengya.context.MengyaClassPathXMLApplicationContext; import di.service.StudentService; public class MySpringAnnotationTest { public static void main(String[] args) { MengyaClassPathXMLApplicationContext ctx = new MengyaClassPathXMLApplicationContext("beans3.xml"); StudentService stuService = (StudentService) ctx.getBean("stuService"); stuService.save(); } }
这个是重点的核心了。
injectObject() 函数是将stuDao和stuService两个Bean保存在属性sigletons里面
annotationInject() 函数是查找StudentServiceImple2类内的@Resource注解,并将StudentDao注入给stuDao属性
package com.mengya.context; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.beanutils.BeanUtils; import com.mengya.spring.annotation.MyResource; import com.mengya.spring.bean.BeanDefinition; import com.mengya.spring.bean.PropertyDefinition; import com.mengya.spring.util.ReadXMLUtil; public class MengyaClassPathXMLApplicationContext { private List<BeanDefinition> beanDefintionList = null; private Map<String, Object> sigletons = new HashMap<String, Object>(); /** * 容器初始化时 传入配置文件名称 读取配置文件..实例化bean * * @param configFileName */ public MengyaClassPathXMLApplicationContext(String configFileName) { beanDefintionList = ReadXMLUtil.readXMLBeanDefintion(configFileName); this.instanceBeans(); this.injectObject(); this.annotationInject(); } /** * 注解实现依赖注入 * */ private void annotationInject() { /** * 遍历bean,获取bean里的所有属性描述对象,遍历属性描述对象数组. * ---获取属性的setter方法.如果该属性setter方法存在,判断方法上是否有MyResource注解, * 如果有,获取注解对象,通过注解对象获取name值 * 如果name值存在:根据name值查找Map中是否有该名称的bean,如果有,调用该属性的setter方法执行注入. * 如果name值不存在:获取该属性的名称,从map中查找是否有此名称的bean. 如果有:调用setter方法注入 * 没有:获取该属性的类型,遍历map查找map中是否有和此属性类型一致的bean,如果有,则执行注入 * * ---获取该属性,判断该属性上是否有MyResource注解 如果有:获取该注解的对象,通过该对象获取name值 * 如果name值存在:根据name值查找map中是否有该bean如果有则执行注入 * 如果name值不存在:获取该属性的名称,查找map中是否有该名称的bean 如果有:执行注入 没有:获取该属性的类型 * 遍历map中判断是否有和该类型一致的bean * */ for (String beanName : sigletons.keySet()) { System.out.println("beanName: " + beanName); Object bean = getBean(beanName); System.out.println("bean:" + bean.toString()); if (null != bean) { try { // 获取所有的属性 PropertyDescriptor pd[] = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors(); for (PropertyDescriptor descriptor : pd) { // 获取set方法 Method setter = descriptor.getWriteMethod(); // 若在set方法设置了MyResource注解 if (null != setter && setter.isAnnotationPresent(MyResource.class)) { MyResource myResource = setter.getAnnotation(MyResource.class); String diName = null; Object diObject = null; // 设置了name属性值 if (null != myResource.name() && !"".equals(myResource.name())) { diName = myResource.name(); } else {// 按默认的属性值装配置 diName = descriptor.getName(); } diObject = getBean(diName); setter.setAccessible(true); setter.invoke(bean, diObject); } } // 获取所有字段 Field[] fields = bean.getClass().getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(MyResource.class)) { MyResource myResource = field.getAnnotation(MyResource.class); String diName = null; Object diObject = null; // 设置了name属性值 if (null != myResource.name() && !"".equals(myResource.name())) { diName = myResource.name(); } else {// 按默认的属性值装配置 diName = field.getName(); } diObject = getBean(diName); field.setAccessible(true); field.set(bean, diObject); } } } catch (Exception e) { e.printStackTrace(); } } } } /** * 注入Bean * */ private void injectObject() { for (BeanDefinition beanDefinition : beanDefintionList) { Object obj = getBean(beanDefinition.getId()); if (null != obj) { List<PropertyDefinition> propertys = beanDefinition.getPropertys(); if (null != propertys && propertys.size() > 0) { try { //通过Java的内省机制获取到对象中所有属性的描述信息 PropertyDescriptor[] ps = Introspector.getBeanInfo(obj.getClass()).getPropertyDescriptors(); for (PropertyDescriptor descriptor : ps) { for (PropertyDefinition property : propertys) { //判断XML文件中解析出来的属性和对象中的属性名称是否一样 if (descriptor.getName().equals(property.getName())) { if (null != property.getRef() && !"".equals(property.getRef())) { Object diObject = getBean(property.getRef()); descriptor.getWriteMethod().invoke(obj, diObject); } else { BeanUtils.setProperty(obj, property.getName(), property.getValue()); } } } } } catch (Exception e) { e.printStackTrace(); } } } } } /** * 实例化Bean * */ private void instanceBeans() { for (BeanDefinition beanDefinition : beanDefintionList) { try { Object obj = Class.forName(beanDefinition.getClassName()).newInstance(); this.sigletons.put(beanDefinition.getId(), obj); } catch (Exception e) { e.printStackTrace(); } } System.out.println("this.sigletons: " + this.sigletons.toString()); } /** * 获取Bean实例 * * @param beanName * @return */ public Object getBean(String beanName) { return this.sigletons.get(beanName); } }