干活 spring依赖注入

http://sumdwang.blog.163.com/blog/static/792969502010102195937569/

使用Spring,可以使用里面的控制反转把依赖对象交给Spring管理,并把依赖对象通过容器注入到组件内部。那么在Spring里面,该如何把对象注入到组件内部呢?
  创建一个PersonDao对象,并把这个对象注入到PersonServiceBean中

Java代码 复制代码
  1. package cn.itcast.dao.impl;   
  2.   
  3. import cn.itcast.dao.PersonDao;   
  4.   
  5. public class PersonDaoBean implements PersonDao {   
  6.     public void add(){   
  7.         System.out.println("执行PersonDaoBean里的add()方法");   
  8.     }   
  9. }  

面向接口编程,所以要把接口抽取出来。
Java代码 复制代码
  1. package cn.itcast.dao;   
  2.   
  3. public interface PersonDao {   
  4.   
  5.     public void add();   
  6.   
  7. }  
接口跟实现类不要放一块,接下来,如何将PersonDaoBean对象注入进PersonServiceBean,注入方式有两种:一种是构造器参数,另一种是通过属性的set方法注入。 下面介绍通过属性的set方法我们该如何注入PersonDaoBean对象

PersonServiceBean.java
Java代码 复制代码
  1. package cn.itcast.service.impl;   
  2.   
  3. import cn.itcast.dao.PersonDao;   
  4. import cn.itcast.service.PersonService;   
  5.   
  6. public class PersonServiceBean implements PersonService {   
  7.     private PersonDao personDao;   
  8.        
  9.     public PersonDao getPersonDao() {   
  10.         return personDao;   
  11.     }   
  12.   
  13.     public void setPersonDao(PersonDao personDao) {   
  14.         this.personDao = personDao;   
  15.     }   
  16.        
  17.     public void save(){   
  18.         personDao.add();   
  19.     }   
  20. }  
大家可以看到,在服务层的这个类里面,我们并没有看到PersonDaoBean的身影,也就是说我们并不关心这个实现类是谁,我们通过PersonDao这个接口去引用注入进来的对象,在通过接口调用它的方法。这样的话,服务层的组件和DAO层的组件已经进行彻底的解耦了。
看下在beans.xml里如何为personDao这个属性注入PersonDaoBean这个bean呢? 首先要把personDao这个bean配置在Spring中

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.        xsi:schemaLocation="http://www.springframework.org/schema/beans   
  5.            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">  
  6.            <bean id="personDao" class="cn.itcast.dao.impl.PersonDaoBean"></bean>  
  7.           <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean">  
  8.             <property name="personDao" ref="personDao"></property>  
  9.           </bean>  
  10. </beans>  

property这个元素就是用于为属性注入值,name填写的是属性的名称
ref填写的值就是我们要注入的bean的名称。Spring会根据这个名称从Spring容器里面得到这个bean,因为这个bean默认在Spring容器实例化后就会被实例化,所以它在容器里面根据ref里的名称得到相应的bean,然后把这个bean通过反射技术就付给了<property name=""/>里面的属性。这就是Spring执行的过程。
我们看下我们注入的personDao这个bean是否能够成功注入呢?判断是否能够成功注入很简单,在PersonServiceBean.java里的save方法,调用了personDao.add()方法,如果注入不成功的话,就会出现空指针异常;如果能输出add方法里面打印的那句话,就代表注入是成功的

Java代码 复制代码
  1. package junit.test;   
  2.   
  3. import org.junit.BeforeClass;   
  4. import org.junit.Test;   
  5. import org.springframework.context.support.AbstractApplicationContext;   
  6. import org.springframework.context.support.ClassPathXmlApplicationContext;   
  7.   
  8. import cn.itcast.service.PersonService;   
  9.   
  10. public class SpringTest {   
  11.   
  12.     @BeforeClass  
  13.     public static void setUpBeforeClass() throws Exception {   
  14.     }   
  15.   
  16.     @Test public void instanceSpring(){   
  17.         AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");   
  18.         PersonService personService = (PersonService)ctx.getBean("personService");   
  19.                 personService.save();   
  20.         ctx.close();   
  21.     }   
  22. }  

运行单元测试代码,控制台输出“执行PersonDaoBean里的add()方法”。说明注入成功了

这时候,大家思考下控制反转这个概念,原先我们对象的创建是由应用本身创建的。现在对象的创建是由容器帮我们创建,并且由容器注入进来,这时候控制权发生了转移,这就是所谓的控制反转。大家印象应该比较深刻了吧?


注入就介绍到这里,有同学可能会问:那么它内部到底是如何实现的呢? 接下来就在原先的传智播客版Spring容器中实现这个过程,解剖一下Spring的内部细节。
首先要建一个java bean,用来存储property的信息,然后property的信息再通过一个集合存在bean里面

PropertyDefinition.java
Java代码 复制代码
  1. package junit.test;   
  2.   
  3. public class PropertyDefinition {   
  4.     private String name;   
  5.     private String ref;   
  6.        
  7.     public PropertyDefinition(String name, String ref) {   
  8.         this.name = name;   
  9.         this.ref = ref;   
  10.     }   
  11.        
  12.     public String getName() {   
  13.         return name;   
  14.     }   
  15.     public void setName(String name) {   
  16.         this.name = name;   
  17.     }   
  18.     public String getRef() {   
  19.         return ref;   
  20.     }   
  21.     public void setRef(String ref) {   
  22.         this.ref = ref;   
  23.     }   
  24.        
  25. }  

BeanDefinition.java
Java代码 复制代码
  1. package junit.test;   
  2.   
  3. import java.util.ArrayList;   
  4. import java.util.List;   
  5.   
  6. public class BeanDefinition {   
  7.     private String id;   
  8.     private String className;   
  9.     private List<PropertyDefinition> propertys = new ArrayList<PropertyDefinition>();   
  10.     //通过一个集合,来存放property的信息   
  11.   
  12.     public BeanDefinition(String id, String className) {   
  13.         this.id = id;   
  14.         this.className = className;   
  15.     }   
  16.     public String getId() {   
  17.         return id;   
  18.     }   
  19.     public void setId(String id) {   
  20.         this.id = id;   
  21.     }   
  22.     public String getClassName() {   
  23.         return className;   
  24.     }   
  25.     public void setClassName(String className) {   
  26.         this.className = className;   
  27.     }   
  28.     public List<PropertyDefinition> getPropertys() {   
  29.         return propertys;   
  30.     }   
  31.     public void setPropertys(List<PropertyDefinition> propertys) {   
  32.         this.propertys = propertys;   
  33.     }   
  34.   
  35. }  

ItcastClassPathXMLApplicationContext.java
Java代码 复制代码
  1. package junit.test;   
  2.   
  3. import java.beans.IntrospectionException;   
  4. import java.beans.Introspector;   
  5. import java.beans.PropertyDescriptor;   
  6. import java.lang.reflect.Method;   
  7. import java.net.URL;   
  8. import java.util.ArrayList;   
  9. import java.util.HashMap;   
  10. import java.util.HashSet;   
  11. import java.util.List;   
  12. import java.util.Map;   
  13.   
  14. import org.dom4j.Document;   
  15. import org.dom4j.Element;   
  16. import org.dom4j.XPath;   
  17. import org.dom4j.io.SAXReader;   
  18.   
  19. /**  
  20.  * 传智播客版的Spring容器  
  21.  */  
  22. public class ItcastClassPathXMLApplicationContext {   
  23.     private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();   
  24.     private Map<String, Object> sigletons = new HashMap<String, Object>();   
  25.   
  26.     // 存放bean实例   
  27.   
  28.     public ItcastClassPathXMLApplicationContext(String filename) {   
  29.         // 模拟内部的实现,首先要读取配置文件,可以用dom4j   
  30.         this.readXML(filename);   
  31.         // 读取完bean之后,Spring要对bean进行实例化,怎么实现实例化呢? 通过反射机制就很容易做到   
  32.         this.instanceBeans();   
  33.         this.injectObject();   
  34.     }   
  35.   
  36.     /**  
  37.      * 实现bean的实例化  
  38.      */  
  39.     private void instanceBeans() {   
  40.         for (BeanDefinition beanDefinition : beanDefines) {   
  41.             try {   
  42.                 if (beanDefinition.getClassName() != null  
  43.                         && !"".equals(beanDefinition.getClassName().trim()))   
  44.                     sigletons.put(beanDefinition.getId(), Class.forName(   
  45.                             beanDefinition.getClassName()).newInstance());   
  46.             } catch (Exception e) {   
  47.                 // 通过反射技术把bean都创建出来   
  48.                 e.printStackTrace();   
  49.             }   
  50.         }   
  51.   
  52.     }   
  53.   
  54.     /**  
  55.      * 为bean对象的属性注入值  
  56.      */  
  57.     private void injectObject() {   
  58.         for (BeanDefinition beanDefinition : beanDefines) {   
  59.             Object bean = sigletons.get(beanDefinition.getId());   
  60.             if (bean != null) {   
  61.                 try {   
  62.                     PropertyDescriptor[] ps = Introspector.getBeanInfo(   
  63.                             bean.getClass()).getPropertyDescriptors();   
  64.                     //Introspector通过这个类可以取得bean的定义信息   
  65.                     for (PropertyDefinition propertyDefinition : beanDefinition   
  66.                             .getPropertys()) {   
  67.                         for (PropertyDescriptor properdesc : ps) {   
  68.                             if (propertyDefinition.getName().equals(properdesc.getName())) {   
  69.                                 Method setter = properdesc.getWriteMethod();// 获取属性的setter方法   
  70.                                                                             // ,private   
  71.                                 if (setter != null) {//属性可能没有set方法,所以这里要判断一下   
  72.                                     Object value = sigletons   
  73.                                             .get(propertyDefinition.getRef());   
  74.                                     setter.setAccessible(true);//如果set方法是私有的话,要设置它允许被访问   
  75.                                     setter.invoke(bean, value);// 把引用对象注入到属性   
  76.                                 }   
  77.                                 break;   
  78.                             }   
  79.                         }   
  80.                     }   
  81.                 } catch (Exception e) {   
  82.                 }   
  83.             }   
  84.         }   
  85.     }   
  86.   
  87.     /**  
  88.      * 读取xml配置文件  
  89.      */  
  90.     private void readXML(String filename) {   
  91.         SAXReader saxReader = new SAXReader();   
  92.         Document document = null;   
  93.         try {   
  94.             URL xmlpath = this.getClass().getClassLoader()   
  95.                     .getResource(filename);   
  96.             document = saxReader.read(xmlpath);   
  97.             Map<String, String> nsMap = new HashMap<String, String>();   
  98.             nsMap.put("ns""http://www.springframework.org/schema/beans");// 加入命名空间   
  99.             XPath xsub = document.createXPath("//ns:beans/ns:bean");// 创建beans/bean查询路径   
  100.             xsub.setNamespaceURIs(nsMap);// 设置命名空间   
  101.             List<Element> beans = xsub.selectNodes(document);// 获取文档下所有bean节点   
  102.             for (Element element : beans) {   
  103.                 String id = element.attributeValue("id");// 获取id属性值   
  104.                 String clazz = element.attributeValue("class"); // 获取class属性值   
  105.                 BeanDefinition beanDefine = new BeanDefinition(id, clazz);   
  106.                 XPath propertysub = element.createXPath("ns:property");   
  107.                 propertysub.setNamespaceURIs(nsMap);// 设置命名空间   
  108.                 List<Element> propertys = propertysub.selectNodes(element);   
  109.                 for (Element property : propertys) {   
  110.                     String propertyName = property.attributeValue("name");   
  111.                     String propertyref = property.attributeValue("ref");   
  112.                     System.out.println(propertyName + " = " + propertyref);   
  113.                     PropertyDefinition propertyDefinition = new PropertyDefinition(   
  114.                             propertyName, propertyref);   
  115.                     beanDefine.getPropertys().add(propertyDefinition);   
  116.                 }   
  117.                 beanDefines.add(beanDefine);   
  118.             }   
  119.         } catch (Exception e) {   
  120.             e.printStackTrace();   
  121.         }   
  122.     }   
  123.   
  124.     /**  
  125.      * 获取bean实例  
  126.      */  
  127.     public Object getBean(String beanName) {   
  128.         return this.sigletons.get(beanName);   
  129.     }   
  130. }  


SpringTest.java
Java代码 复制代码
  1. package junit.test;   
  2.   
  3. import org.junit.BeforeClass;   
  4. import org.junit.Test;   
  5.   
  6. import cn.itcast.service.PersonService;   
  7.   
  8. public class SpringTest {   
  9.   
  10.     @BeforeClass  
  11.     public static void setUpBeforeClass() throws Exception {   
  12.     }   
  13.   
  14.     @Test public void instanceSpring(){   
  15.         ItcastClassPathXMLApplicationContext ctx = new ItcastClassPathXMLApplicationContext("beans.xml");   
  16.         PersonService personService = (PersonService)ctx.getBean("personService");   
  17.                 //通过传智播客版的Spring容器得到这个bean   
  18.         personService.save();   
  19.     }   
  20. }  
运行单元测试代码,如果是空指针异常,则注入不成功;如果注入成功,则打印add里面的语句。
结果控制台输出是:
personDao = personDao
执行PersonDaoBean里的add()方法

成功了,通过传智播客版的类也可以模拟Spring的注入功能,相信大家通过参看这段代码后,会对Spring如何注入依赖对象会很清楚了。这也是为什么传智播客的同学出去后,对原理理解的那么透彻了。。。

代码如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值