在Spring学习笔记(3)中剖析了Spring管理Bean的原理,下面解释下Spring依赖注入的原理
在进行依赖注入时,我们的配置文件如下配置:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <bean id="mySqlDAO" class="com.szy.spring.dao.UserDAO4MySqlImpl"/> <bean id="oracleDAO" class="com.szy.spring.dao.UserDAO4OracleImpl"/> <bean id="userService" class="com.szy.spring.service.UserServiceImpl"> <!--构造方法注入 <property name="userDAO" ref="mySqlDAO"></property> --> <property name="userDAO" ref="oracleDAO"></property> </bean> </beans>
根据配置文件信息,我们首先需要建立一个Bean类,用来保存bean节点的信息:
package com.szy.spring.bean; import java.util.List; public class Bean { private String id; private String className; private List<Property> propertyList; public Bean(String id, String className, List<Property> propertyList) { super(); this.id = id; this.className = className; this.propertyList = propertyList; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public List<Property> getPropertyList() { return propertyList; } public void setPropertyList(List<Property> propertyList) { this.propertyList = propertyList; } }
此外,由于bean下存在property信息,因此我们还需要建立property类
package com.szy.spring.bean; public class Property { private String name; private String ref; public Property(String name, String ref) { super(); this.name = name; this.ref = ref; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRef() { return ref; } public void setRef(String ref) { this.ref = ref; } }
在Spring学习笔记(3)中,我们在读取xml文件时bean节点下面是不存在property节点的,因此在这里我们需要修改readXML()方法:
/** * 读取xml配置文件 * @param fileName 配置文件名 */ private void readXML(String fileName) { // 寻找配置文件 URL xmlPath = this.getClass().getClassLoader().getResource(fileName); Document doc = null; Element root = null; try { SAXBuilder sb = new SAXBuilder(false); doc = sb.build(new FileInputStream(new File(xmlPath.toURI()))); // 设置命名空间 Namespace xhtml = Namespace.getNamespace("xhtml", "http://www.springframework.org/schema/beans"); root = doc.getRootElement(); // 获取根元素 List<Element> bList = root.getChildren("bean", xhtml); //获取全部bean节点 for (Element beanElement : bList)// 遍历节点,取得每个节点的属性 { String id = beanElement.getAttributeValue("id"); String className = beanElement.getAttributeValue("class"); //获得每个bean下面的属性 List<Element> pList = beanElement .getChildren("property", xhtml); List<Property> propertyList = new ArrayList<Property>(); //存储属性信息 if (pList.size() > 0) //如果存在属性 { for (Element propertyElement : pList) //遍历属性节点 { String name = propertyElement.getAttributeValue("name"); String ref = propertyElement.getAttributeValue("ref"); Property property = new Property(name, ref); propertyList.add(property); //保存属性节点 } } Bean bean = new Bean(id, className, propertyList); beanList.add(bean); } } catch (Exception e) { e.printStackTrace(); } }
读取完配置文件后我们还是需要对bean进行实例化的,这方法和Spring学习笔记(3)中的instanceBeans()方法一样。下面就是我们需要给bean属性进行注入,实现方法如下:
/** * 为bean对象的属性注入值 */ public void injectObject() { for (Bean bean : beanList) { Object object = beanObject.get(bean.getId()); //获取bean的实例 if (object != null) { try { PropertyDescriptor[] ps = Introspector.getBeanInfo( object.getClass()).getPropertyDescriptors(); //取得bean的属性描述 for (Property property : bean.getPropertyList()) //获取bean节点的属性 { for (PropertyDescriptor properdesc : ps) { if (property.getName().equals(properdesc.getName())) { Method setter = properdesc.getWriteMethod();//获取属性的setter方法 ,private if (setter != null) { Object value = beanObject.get(property.getRef()); //取得值 setter.setAccessible(true); //设置为允许访问 setter.invoke(object, value);//把引用对象注入到属性 } break; } } } } catch (Exception e) { e.printStackTrace(); } } }
我们进行测试:
MyClassPathXMLApplicationContext ctx=new MyClassPathXMLApplicationContext("applicationContext.xml"); UserService service=(UserService)ctx.getBean("userService"); service.show();
运行输出
OracleDAO Implement
上面仅是简单的演示了Spring依赖注入的原理,但是在实际操作中还需要考虑很对其它因素,在此就不进行讨论了。