spring 控制反转与依赖注入原理-学习笔记

在Spring中有两个非常重要的概念,控制反转和依赖注入;控制反转将依赖对象的创建和管理交由Spring容器,而依赖注入则是在控制反转的基础上将Spring容器管理的依赖对象注入到应用之中;

所谓依赖注入:在运行期,由外部容器动态将依赖对象注入到组件中。

XML文件解析 + Java反射技术;

首先是XML文件的解析(dom4j),Spring框架对于配置文件的选择是XML文件,根据Spring的规范,配置文件的命名是没有特殊要求的,只是在文件的放置位置上有两种选择;类路径下或者操作系统文件目录下(大多数情况是放到类路径下)。

对于Spring的控制反转和依赖注入来说,唯一使用的是配置文件中的<bean>标签,通过这个标签,Spring就完成了对象的创建和依赖对象的注入工作;

1、首先对于配置文件中的<bean>节点,在Spring框架中存在一个对用的定义接口,叫做BeanDefinition;子啊个类定义了获得<bean>节点中出现的所有属性的方法,例如classNam、scope、factory-method、lazy-init 等等属性;

2、对于<bean>节点的子节点property则完成了属性注入的功能;属性注入有三种方式,构造器注入、属性setter方法注入和注解方式注入;

3、如果是setter方法注入,对于类属性XML配置文件中有两种方法,一是使用property节点的ref属性,一是使用property几点的子节点bean进行内部bean配置;如果是对于基本数据类型进行配置,那么要是用property节点的value属性;


定义自己的关于bean节点、property节点的pojo类文件;

使用注入DOM4J等开源包讲配置文件解析读入;

使用Java的反射技术讲配置文件中的信息setter到我们需要的属性中去;common-beanutils.jar

 

 

Xml代码  收藏代码
  1. <context:component-scan base-package="com.sample"/>  
  2. <bean id="personService" class="com.spring.junit.test.impl.PersonServiceImpl"></bean>  
  3. <bean id="stockService" class="com.spring.junit.test.impl.StockServiceImpl"></bean>  
  4.   
  5. <bean id="personServiceFactory" class="com.spring.junit.test.impl.PersonServiceBeanFactory" factory-method="createPersonServiceBeanFactory"></bean>  
  6.   
  7. <bean id="personServiceFactory2" class="com.spring.junit.test.impl.PersonServiceBeanFactory"></bean>  
  8. <bean id="stockServiceFactory" factory-bean="personServiceFactory2" factory-method="createStockServiceBeanFactory"></bean>  
  9.   
  10. <bean id="randomBean" class="com.spring.junit.bean.StaticFactoryBean" factory-method="createRandom" scope="prototype"></bean>  
  11.   
  12. <!-- 集合类型的注入 -->  
  13.   
  14. 通过setter方法注入  
  15. <bean id="user" class="com.sample.bean.User"></bean>  
  16. <bean id="personDao" class="com.sample.dao.impl.PersonDaoBeanImpl"></bean>  
  17. <bean id="personService" class="com.sample.service.impl.PersonServiceBeanImpl">  
  18.      
  19.    <property name="personDao" ref="personDao"></property>  
  20.    <property name="name" value="jackjson_xu_test"></property>  
  21.    <property name="id" value="108"></property>  
  22.    <property name="sets">  
  23.        <set>  
  24.            <value>第一个</value>  
  25.            <value>第二个</value>  
  26.            <value>第三个</value>  
  27.        </set>  
  28.    </property>  
  29.    <property name="lists">  
  30.        <list>  
  31.            <value>第一個list元素</value>  
  32.            <value>第二個list元素</value>  
  33.            <value>第三個list元素</value>  
  34.              
  35.        </list>  
  36.    </property>  
  37.    <property name="properties">  
  38.        <props>  
  39.            <prop key="key1">value1</prop>  
  40.            <prop key="key2">value2</prop>  
  41.            <prop key="key3">value3</prop>  
  42.              
  43.        </props>  
  44.    </property>  
  45.    <property name="maps">  
  46.        <map>  
  47.            <entry key="key-1" value="value-1"></entry>  
  48.            <entry key="key-2" value="value-2"></entry>  
  49.            <entry key="key-3" value="value-3"></entry>  
  50.            <entry key="key-4" value="value-4"></entry>  
  51.        </map>  
  52.    </property>  
  53.    <property name="users">  
  54.        <map>  
  55.            <entry key="U_1001">  
  56.                <ref bean="user"/>  
  57.            </entry>  
  58.            <entry key="U_1002">  
  59.                   <ref bean="user"/>  
  60.               </entry>  
  61.        </map>  
  62.    </property>  
  63. </bean>  
  64. <!-- 采用内部bean的方式注入 -->  
  65.   
  66. <bean id="personService" class="com.sample.service.impl.PersonServiceBeanImpl">  
  67.    <property name="personDao">  
  68.        <bean class="com.sample.dao.impl.PersonDaoBeanImpl"/>  
  69.    </property>  
  70.    <property name="name" value="jackjson_xu_test"></property>  
  71.    <property name="id" value="100"></property>  
  72. </bean>  
  73.   
  74.   
  75. <!-- 构造器注入方式 -->  
  76.   
  77. <bean id="personDao" class="com.sample.dao.impl.PersonDaoBeanImpl"></bean>  
  78.    <bean id="personService2" class="com.sample.service.impl.PersonServiceBeanImpl2" autowire="byType">  
  79.        <constructor-arg index="0" type="com.sample.dao.IPersonDao" ref="personDao"></constructor-arg>  
  80.        <constructor-arg index="1" type="java.lang.String" value="http://www.woyo.com"></constructor-arg>  
  81.    </bean>  
  82.    

 package com.sample.junit;

Java代码  收藏代码
  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3. /** 
  4.  * Spring xml 属性的方法 
  5.  * @author DY 
  6.  * 
  7.  */  
  8. public class BeanDefinition {  
  9.     private String id;  
  10.     private String className;  
  11.     private List<PropertyDefinition> propertys = new ArrayList<PropertyDefinition>();  
  12.   
  13.     public BeanDefinition(String id, String className) {  
  14.         this.id = id;  
  15.         this.className = className;  
  16.     }  
  17.   
  18.     public String getId() {  
  19.         return id;  
  20.     }  
  21.   
  22.     public void setId(String id) {  
  23.         this.id = id;  
  24.     }  
  25.   
  26.     public String getClassName() {  
  27.         return className;  
  28.     }  
  29.   
  30.     public void setClassName(String className) {  
  31.         this.className = className;  
  32.     }  
  33.   
  34.     public List<PropertyDefinition> getPropertys() {  
  35.         return propertys;  
  36.     }  
  37.   
  38.     public void setPropertys(List<PropertyDefinition> propertys) {  
  39.         this.propertys = propertys;  
  40.     }  
  41. }  

 package com.sample.junit;

Java代码  收藏代码
  1. /** 
  2.  * Spring xml bean 子节点property属性方法 
  3.  *  
  4.  * @author DY 
  5.  *  
  6.  */  
  7. public class PropertyDefinition {  
  8.     private String name;  
  9.     private String ref;  
  10.     private String value;  
  11.   
  12.     public PropertyDefinition(String name, String ref, String value) {  
  13.         this.name = name;  
  14.         this.ref = ref;  
  15.         this.value = value;  
  16.     }  
  17.   
  18.     public String getName() {  
  19.         return name;  
  20.     }  
  21.   
  22.     public void setName(String name) {  
  23.         this.name = name;  
  24.     }  
  25.   
  26.     public String getRef() {  
  27.         return ref;  
  28.     }  
  29.   
  30.     public void setRef(String ref) {  
  31.         this.ref = ref;  
  32.     }  
  33.   
  34.     public String getValue() {  
  35.         return value;  
  36.     }  
  37.   
  38.     public void setValue(String value) {  
  39.         this.value = value;  
  40.     }  
  41.   
  42. }  

 package com.sample.junit;

Java代码  收藏代码
  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.   
  11. import org.apache.commons.beanutils.ConvertUtils;  
  12. import org.apache.log4j.Logger;  
  13. import org.dom4j.Document;  
  14. import org.dom4j.Element;  
  15. import org.dom4j.XPath;  
  16. import org.dom4j.io.SAXReader;  
  17. /** 
  18.  * spring装配applicationContext.xml文件 
  19.  * @author DY 
  20.  * 
  21.  */  
  22. public class SampleClassPathXMLApplicationContext {  
  23.     private Logger logger = Logger.getLogger(SampleClassPathXMLApplicationContext.class);  
  24.     private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();  
  25.     private Map<String, Object> sigletons = new HashMap<String, Object>();  
  26.   
  27.     public SampleClassPathXMLApplicationContext(String filename) {  
  28.         this.readXML(filename);  
  29.         this.instanceBeans();   //bean的实例化 Class.forName().newInstance()  
  30.         this.annotationInject();//注解  
  31.         this.injectObject();    //bean对象的属性注入值  
  32.     }  
  33.     /** 
  34.      * 注解处理器 
  35.      * 如果注解SampleResouce配置了name属性,则根据name所指定的名称获取要注入的实例引用 
  36.      * 如果注解SampleResouce没有配置name属性,则根据属性所属类型来扫描配置文件获取要注入的实例引用 
  37.      */  
  38.     private void annotationInject() {  
  39.         for (String beanName : sigletons.keySet()) {  
  40.             Object bean = sigletons.get(beanName);  
  41.             if (bean != null) {  
  42.                 this.propertyAnnotation(bean);  
  43.                 this.fieldAnnotation(bean);  
  44.             }  
  45.         }  
  46.     }  
  47.     /** 
  48.      * 处理在所有set方法加入的注解 
  49.      * @param bean 处理的bean对象 
  50.      */  
  51.     private void propertyAnnotation(Object bean) {  
  52.         try {  
  53.             //获取其属性的描述  
  54.             PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();  
  55.             for (PropertyDescriptor properdesc : ps) {  
  56.                 //获取属性的setter方法  
  57.                 Method setter = properdesc.getWriteMethod();  
  58.                 //setter方法上是否存在注解  
  59.                 if (setter != null && setter.isAnnotationPresent(SampleResource.class)) {  
  60.                     //获取当前注解,判断name属性是否为空  
  61.                     SampleResource resouce = setter.getAnnotation(SampleResource.class);  
  62.                     Object value = null;  
  63.                     if (resouce.name() != null && !"".equals(resouce.name())) {  
  64.                         value = sigletons.get(resouce.name());  
  65.                         setter.setAccessible(true);  
  66.                         setter.invoke(bean, value);//把引用对象注入到属性  
  67.                     } else {//如果当前属性没有指定name,则根据类型匹配  
  68.                         value = sigletons.get(resouce.name());  
  69.                         if (value == null) {  
  70.                             for (String key : sigletons.keySet()) {  
  71.                                 //判断当前属性所属类型是否在配置文件中存在  
  72.                                 if (properdesc.getPropertyType().isAssignableFrom(sigletons.get(key).getClass())) {  
  73.                                     value = sigletons.get(key); //获取类型匹配的实例对象  
  74.                                 }  
  75.                             }  
  76.                         }  
  77.                         //允许访问private方法  
  78.                         setter.setAccessible(true);  
  79.                         //把引用对象注入属性  
  80.                         setter.invoke(bean, value);  
  81.                     }  
  82.                 }  
  83.             }  
  84.         } catch (Exception e) {  
  85.             logger.error(e.getLocalizedMessage());  
  86.         }  
  87.     }  
  88.     /** 
  89.      * 处理在字段上的注解 
  90.      * @param bean 
  91.      */  
  92.     private void fieldAnnotation (Object bean) {  
  93.         try {  
  94.             //获取全部属性对象数组  
  95.             Field[] fields = bean.getClass().getFields();  
  96.             for (Field field : fields) {  
  97.                 if (field.isAnnotationPresent(SampleResource.class)) {  
  98.                     SampleResource resouce = field.getAnnotation(SampleResource.class);  
  99.                     Object value = null;  
  100.                     if (resouce.name() != null && !"".equals(resouce.name())) {  
  101.                         value = sigletons.get(resouce.name());  
  102.                     } else {  
  103.                         value = sigletons.get(field.getName());  
  104.                         if (value == null) {  
  105.                             for (String key : sigletons.keySet()) {  
  106.                                 //根据字段类型匹配  
  107.                                 if (field.getType().isAssignableFrom(sigletons.get(key).getClass())) {  
  108.                                     value = sigletons.get(key);  
  109.                                     break;  
  110.                                 }  
  111.                             }  
  112.                         }  
  113.                     }  
  114.                     field.setAccessible(true);  
  115.                     field.set(bean, value);  
  116.                 }  
  117.             }  
  118.         } catch (Exception e) {  
  119.             e.getLocalizedMessage();  
  120.             logger.error("字段注解解析异常:" + e.getLocalizedMessage());  
  121.         }  
  122.     }  
  123.     /** 
  124.      * 为bean对象的属性注入值 
  125.      */  
  126.     private void injectObject() {  
  127.         for (BeanDefinition beanDefinition : beanDefines) {  
  128.             Object bean = sigletons.get(beanDefinition.getId());  
  129.             if (bean != null) {  
  130.                 try {  
  131.                     PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();  
  132.                     for (PropertyDefinition propertyDefinition : beanDefinition.getPropertys()) {  
  133.                         for (PropertyDescriptor properdesc : ps) {  
  134.                             if (propertyDefinition.getName().equals(properdesc.getName())) {  
  135.                                 Method setter = properdesc.getWriteMethod();// 获取属性的setter方法  
  136.                                 if (setter != null) {  
  137.                                     Object value = null;  
  138.                                     if (propertyDefinition.getRef() != null && !"".equals(propertyDefinition.getRef().trim())) {  
  139.                                         value = sigletons.get(propertyDefinition.getRef());  
  140.                                     } else {  
  141.                                         value = ConvertUtils.convert(propertyDefinition.getValue(), properdesc.getPropertyType());  
  142.                                     }  
  143.                                     setter.setAccessible(true);//私有方法给与访问权限  
  144.                                     setter.invoke(bean, value);// 把引用对象注入到属性  
  145.                                 }  
  146.                                 break;  
  147.                             }  
  148.                         }  
  149.                     }  
  150.                 } catch (Exception e) {  
  151.                 }  
  152.             }  
  153.         }  
  154.     }  
  155.   
  156.     /** 
  157.      * 完成bean的实例化 
  158.      */  
  159.     private void instanceBeans() {  
  160.         for (BeanDefinition beanDefinition : beanDefines) {  
  161.             try {  
  162.                 if (beanDefinition.getClassName() != null  
  163.                         && !"".equals(beanDefinition.getClassName().trim()))  
  164.                     sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance());  
  165.             } catch (Exception e) {  
  166.                 e.printStackTrace();  
  167.             }  
  168.         }  
  169.     }  
  170.   
  171.     /** 
  172.      * 读取xml配置文件 
  173.      *  
  174.      * @param filename 
  175.      */  
  176.     private void readXML(String filename) {  
  177.         SAXReader saxReader = new SAXReader();  
  178.         Document document = null;  
  179.         try {  
  180.             URL xmlpath = this.getClass().getClassLoader().getResource(filename);  
  181.             document = saxReader.read(xmlpath);  
  182.             Map<String, String> nsMap = new HashMap<String, String>();  
  183.             nsMap.put("ns""http://www.springframework.org/schema/beans");// 加入命名空间  
  184.             XPath xsub = document.createXPath("//ns:beans/ns:bean");// 创建beans/bean查询路径  
  185.             xsub.setNamespaceURIs(nsMap);// 设置命名空间  
  186.             List<Element> beans = xsub.selectNodes(document);// 获取文档下所有bean节点  
  187.             for (Element element : beans) {  
  188.                 String id = element.attributeValue("id");// 获取id属性值  
  189.                 String clazz = element.attributeValue("class"); // 获取class属性值  
  190.                 BeanDefinition beanDefine = new BeanDefinition(id, clazz);  
  191.                 XPath propertysub = element.createXPath("ns:property");  
  192.                 propertysub.setNamespaceURIs(nsMap);// 设置命名空间  
  193.                 List<Element> propertys = propertysub.selectNodes(element);  
  194.                 for (Element property : propertys) {  
  195.                     String propertyName = property.attributeValue("name");  
  196.                     String propertyref = property.attributeValue("ref");  
  197.                     String propertyValue = property.attributeValue("value");  
  198.                     PropertyDefinition propertyDefinition = new PropertyDefinition(propertyName, propertyref, propertyValue);  
  199.                     beanDefine.getPropertys().add(propertyDefinition);  
  200.                     System.out.println("propertyName:" + propertyName + "|propertyref:" + propertyref + "|propertyValue:" + propertyValue);  
  201.                 }  
  202.                 beanDefines.add(beanDefine);  
  203.             }  
  204.         } catch (Exception e) {  
  205.             e.printStackTrace();  
  206.         }  
  207.     }  
  208.   
  209.     /** 
  210.      * 获取bean实例 
  211.      *  
  212.      * @param beanName 
  213.      * @return 
  214.      */  
  215.     public Object getBean(String beanName) {  
  216.         return this.sigletons.get(beanName);  
  217.     }  
  218. }  

 package com.sample.junit;

Java代码  收藏代码
  1. import org.junit.BeforeClass;  
  2. import org.junit.Test;  
  3. import org.springframework.context.ApplicationContext;  
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  5.   
  6. import com.sample.service.IPersonService;  
  7.   
  8. public class SpringTest {  
  9.   
  10.     static ApplicationContext ctx = null;  
  11.     @BeforeClass  
  12.     public static void setUpBeforeClass() throws Exception {  
  13.         ctx = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});  
  14.     }  
  15.       
  16.       
  17.     @Test public void instanceSpring(){  
  18.         IPersonService personService = (IPersonService)ctx.getBean("personService");  
  19.         System.out.println(personService);  
  20.         personService.save();  
  21.     }  
  22.       
  23.   
  24. }  
posted @ 2014-11-11 18:29  飞扬的薰衣草  阅读(257)  评论(0编辑  收藏  举报