1.创建一个PersonDao对象,如下代码:
package cn.itcast.dao;
public interface PersonDao {
public void add();
}
package cn.itcast.dao.impl;
import cn.itcast.dao.PersonDao;
public class PersonDaoBean implements PersonDao {
public void add(){
System.out.println("执行PersonDaoBean中的add()方法.");
}
}
2.将PersonDao对象注入到PersonService中
第一种,通过setter方法
package cn.itcast.service.impl;
import cn.itcast.dao.PersonDao;
import cn.itcast.service.PersonService;
public class PersonServiceBean implements PersonService {
private PersonDao personDao;
public void setPersonDao(PersonDao personDao){
this.personDao = personDao;
}
@Override
public void save() {
personDao.add();
}
}
这里并没有出现PersonDaoBean,实现了完全解耦。那么如何在配置文件中注入PersonDaoBean呢?
<bean id="personDao" class="cn.itcast.dao.impl.PersonDaoBean"></bean>
<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"
init-method="init" destroy-method="destroy">
<property name="personDao" ref="personDao"></property><!-- 注入 -->
</bean>
由容器帮我们创建依赖对象,并且由容器注入进来,这就是控制反转。
它的内部是如何实现注入过程的呢?
<property name="personDao" ref="personDao"></property>
在bean,元素底下是有多个属性元素的。我们也可以指定多个属性,为多个属性注入值。
我们可以建立一个属性的javaBean,来存放属性的信息,然后将属性的javaBean放入一个集合,存放到Bean中。
然后修改读取配置文件的方法,创建查询路径。具体添加代码如下:
XPath propertysub = element.createXPath("ns:property"); // 通过相对路径创建查询路径
propertysub.setNamespaceURIs(nsMap); // 设置命名空间
List<Element> properties = propertysub.selectNodes(element);
for(Element property : properties) {
String propertyName = property.attributeValue("name");
String propertyRef = property.attributeValue("ref");
System.out.println("propertyName : " + propertyName + " propertyRef: " + propertyRef); // 用于测试
PropertyDefinition propertyDefinition = new PropertyDefinition(propertyName, propertyRef);
beanDefine.getProperties().add(propertyDefinition);
}
测试代码:
@Test
public void instanceSpring() {
ItcastClassPathXMLApplicationContext ctx = new ItcastClassPathXMLApplicationContext("beans.xml");
}
后台打印结果为:
propertyName : personDao propertyRef: personDao
我被实例化了...
怎样根据ref的值将bean注入到有属性指令的bean里面去呢?现在我们来处理注入功能
可以用一下代码实现:
/**
* 为bean对象的属性注入值
*/
private void injectObjec() {
// 循环所有的bean
for(BeanDefinition beanDefinition : beanDefines) {
// 根据beanDefinition的id获得实例化的bean
Object bean = sigletons.get(beanDefinition.getId());
if(bean != null) {
try {
// 取得bean实例的属性描述
PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
//取得配置文件bean里面的所有属性定义
for(PropertyDefinition propertyDefinition : beanDefinition.getProperties()){
// 判读这个属性是否在bean定义的属性里面,如果存在,再通过反射技术把这个值注入进去。
for(PropertyDescriptor properdesc : ps) {
if(propertyDefinition.getName().equals(properdesc.getName())) {
Method setter = properdesc.getWriteMethod(); // 获取属性的setter方法
if(setter!=null){
Object value = sigletons.get(propertyDefinition.getRef());
setter.setAccessible(true); // 当setter方法为私有方法时,设置它允许访问
setter.invoke(bean, value); // 把引用对象注入到属性中
}
break;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
再来编写测试代码,
@Test
public void instanceSpring() {
ItcastClassPathXMLApplicationContext ctx = new ItcastClassPathXMLApplicationContext("beans.xml");
PersonService personService = (PersonService)ctx.getBean("personService");
personService.save();
}
如果后台打印出了PersonDaoBean中的add方法的输出语句,则表示注入成功。测试结果为:
整个就是依赖注入的原理了。