控制反转(Inversion of Control):在依赖注入的模式下,创建被调用者的工作不再由调用者来完成,因此称为控制反转;依赖注入(Dependency Injection):创建被调用者的实例通常由Spring容器来完成,然后注入调用者,因此称为依赖注入。不管是依赖注入,还是控制反转,都说明Spring采用动态、灵活的方式管理对象。为了更好地理解这一概念,下面编码模拟Spring依赖注入的原理。

1、首先,写一dao接口及其实现类(这里将两个不同的类代码合在了一起):

  1. public interface PersonDao { 
  2.     public void add(); 
  3.  
  4. public class PersonDaoImpl implements PersonDao { 
  5.  
  6.     @Override 
  7.     public void add() { 
  8.         System.out.println("执行PersonDaoImpl中的add方法!"); 
  9.     } 
  10.  

2、写一service接口及其实现类(这里将两个不同的类代码合在了一起):

  1. public interface PersonService { 
  2.     public void save(); 
  3.  
  4. public class PersonServiceImpl implements PersonService { 
  5.  
  6.     private PersonDao personDao; 
  7.     private int id;  
  8.     private String name; 
  9.  
  10.     public PersonDao getPersonDao() { 
  11.         return personDao; 
  12.     } 
  13.  
  14.     public void setPersonDao(PersonDao personDao) { 
  15.         this.personDao = personDao; 
  16.     } 
  17.  
  18.     public int getId() { 
  19.         return id; 
  20.     } 
  21.  
  22.     public void setId(int id) { 
  23.         this.id = id; 
  24.     } 
  25.  
  26.     public String getName() { 
  27.         return name; 
  28.     } 
  29.  
  30.     public void setName(String name) { 
  31.         this.name = name; 
  32.     } 
  33.  
  34.     @Override 
  35.     public void save() { 
  36.         personDao.add(); 
  37.         System.out.println("id=" + id + ",name=" + name); 
  38.     } 

3、beans.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.  
  7.     <bean id="personDao" class="com.wgy.dao.impl.PersonDaoImpl" /> 
  8.     <bean id="personService" class="com.wgy.service.impl.PersonServiceImpl"> 
  9.         <property name="personDao" ref="personDao" /> 
  10.         <property name="name" value="wgy" /> <!-- 基本属性值的注入 --> 
  11.         <property name="id" value="88" /> 
  12.     </bean> 
  13. </beans> 

4、PropertyDefinition类(封装从beans.xml中读取到的bean节点下的property信息)

  1. public class PropertyDefinition { 
  2.  
  3.     private String name; 
  4.     private String ref; 
  5.     private String value; 
  6.  
  7.     public PropertyDefinition(String name, String ref, String value) { 
  8.         this.name = name; 
  9.         this.ref = ref; 
  10.         this.value = value; 
  11.     } 
  12.  
  13.     public String getName() { 
  14.         return name; 
  15.     } 
  16.  
  17.     public void setName(String name) { 
  18.         this.name = name; 
  19.     } 
  20.  
  21.     public String getRef() { 
  22.         return ref; 
  23.     } 
  24.  
  25.     public void setRef(String ref) { 
  26.         this.ref = ref; 
  27.     } 
  28.  
  29.     public String getValue() { 
  30.         return value; 
  31.     } 
  32.  
  33.     public void setValue(String value) { 
  34.         this.value = value; 
  35.     } 
  36.  

5、BeanDefinition类(封装从beans.xml中读取到的bean信息)

  1. public class BeanDefinition { 
  2.  
  3.     private String id; 
  4.     private String className; 
  5.     private List<PropertyDefinition> propertys = new ArrayList<PropertyDefinition>(); 
  6.  
  7.     public BeanDefinition(String id, String className) { 
  8.         this.id = id; 
  9.         this.className = className; 
  10.     } 
  11.  
  12.     public String getId() { 
  13.         return id; 
  14.     } 
  15.  
  16.     public void setId(String id) { 
  17.         this.id = id; 
  18.     } 
  19.  
  20.     public String getClassName() { 
  21.         return className; 
  22.     } 
  23.  
  24.     public void setClassName(String className) { 
  25.         this.className = className; 
  26.     } 
  27.  
  28.     public List<PropertyDefinition> getPropertys() { 
  29.         return propertys; 
  30.     } 
  31.  
  32.     public void setPropertys(List<PropertyDefinition> propertys) { 
  33.         this.propertys = propertys; 
  34.     } 
  35.  

6、MyClassPathXmlAppCtx类( 自定义容器:模拟ClassPathXmlApplicationContext类的作用)

  1. public class MyClassPathXmlAppCtx { 
  2.  
  3.     private List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>(); 
  4.     private Map<String, Object> instances = new HashMap<String, Object>(); 
  5.  
  6.     public MyClassPathXmlAppCtx(String filename) { 
  7.         readXML(filename); 
  8.         instanceBeans(); 
  9.         injectObject(); 
  10.     } 
  11.  
  12.     /** 
  13.      * 使用dom4j解析beans.xml文件 
  14.      */ 
  15.     @SuppressWarnings("unchecked"
  16.     private void readXML(String filename) { 
  17.         SAXReader saxReader = new SAXReader(); 
  18.         Document document = null
  19.         URL xmlPath = this.getClass().getClassLoader().getResource(filename); 
  20.         try { 
  21.             document = saxReader.read(xmlPath); 
  22.         } catch (Exception e) { 
  23.             e.printStackTrace(); 
  24.         } 
  25.  
  26.         Map<String, String> nsMap = new HashMap<String, String>(); 
  27.         nsMap.put("ns""http://www.springframework.org/schema/beans");// 加入命名空间 
  28.         XPath xsub = document.createXPath("//ns:beans/ns:bean");// 创建beans/bean查询路径 
  29.         xsub.setNamespaceURIs(nsMap);// 设置命名空间 
  30.         List<Element> beans = xsub.selectNodes(document);// 获取文档下所有bean节点 
  31.         for (Element bean : beans) { 
  32.             String id = bean.attributeValue("id");// 获取id属性值 
  33.             String clazz = bean.attributeValue("class");// 获取class属性值 
  34.             BeanDefinition beanDefinition = new BeanDefinition(id, clazz); 
  35.  
  36.             XPath proPath = document.createXPath("ns:property"); 
  37.             proPath.setNamespaceURIs(nsMap); 
  38.             List<Element> propertys = proPath.selectNodes(bean); 
  39.             for (Element property : propertys) { 
  40.                 String propertyName = property.attributeValue("name"); 
  41.                 String propertyRef = property.attributeValue("ref"); 
  42.                 String propertyValue = property.attributeValue("value"); 
  43.                 PropertyDefinition propDefinition = new PropertyDefinition( 
  44.                         propertyName, propertyRef, propertyValue); 
  45.                 beanDefinition.getPropertys().add(propDefinition); 
  46.             } 
  47.             beanDefinitions.add(beanDefinition); 
  48.         } 
  49.     } 
  50.  
  51.     /** 
  52.      * 完成bean的实例化 
  53.      */ 
  54.     private void instanceBeans() { 
  55.         for (BeanDefinition beanDefinition : beanDefinitions) { 
  56.             String className = beanDefinition.getClassName(); 
  57.             if (null != className && !"".equals(className.trim())) { 
  58.                 System.out.println(className); 
  59.                 try { 
  60.                     instances.put(beanDefinition.getId(), 
  61.                             Class.forName(className).newInstance()); 
  62.                 } catch (Exception e) { 
  63.                     e.printStackTrace(); 
  64.                 } 
  65.             } 
  66.         } 
  67.     } 
  68.  
  69.     /** 
  70.      * 为bean对象的属性注入值 
  71.      */ 
  72.     private void injectObject() { 
  73.         for (BeanDefinition beanDefinition : beanDefinitions) { 
  74.             Object bean = instances.get(beanDefinition.getId()); 
  75.             if (bean != null) { 
  76.                 try { 
  77.                     PropertyDescriptor[] pds = Introspector.getBeanInfo( 
  78.                             bean.getClass()).getPropertyDescriptors(); 
  79.                     for (PropertyDefinition propertyDefinition : beanDefinition 
  80.                             .getPropertys()) { 
  81.                         for (PropertyDescriptor pd : pds) { 
  82.                             if (propertyDefinition.getName().equals( 
  83.                                     pd.getName())) { 
  84.                                 Method setter = pd.getWriteMethod(); // 获取属性的setter方法 
  85.                                 // setter.setAccessible(true); 
  86.                                 if (setter != null) { 
  87.                                     Object value = null
  88.                                     String ref = propertyDefinition.getRef(); 
  89.                                     if (ref != null && !"".equals(ref)) { 
  90.                                         value = instances 
  91.                                                 .get(propertyDefinition 
  92.                                                         .getRef()); 
  93.                                     } else { 
  94.                                         value = ConvertUtils.convert( 
  95.                                                 propertyDefinition.getValue(), 
  96.                                                 pd.getPropertyType()); 
  97.                                     } 
  98.                                     setter.invoke(bean, value); // 把引用对象注入到属性 
  99.                                 } 
  100.                                 break
  101.                             } 
  102.                         } 
  103.                     } 
  104.                 } catch (Exception e) { 
  105.                     // TODO Auto-generated catch block 
  106.                     e.printStackTrace(); 
  107.                 } 
  108.             } 
  109.         } 
  110.     } 
  111.  
  112.     /** 
  113.      * 获取bean的实例 
  114.      */ 
  115.     public Object getBean(String beanName) { 
  116.         return instances.get(beanName); 
  117.     } 

7、写一单元测试方法:

  1. @Test 
  2. public void instanceSpring() { 
  3.     // ApplicationContext ctx = new 
  4.     // ClassPathXmlApplicationContext("beans.xml"); 
  5.     MyClassPathXmlAppCtx ctx = new MyClassPathXmlAppCtx("beans.xml"); 
  6.     PersonService personService = (PersonService) ctx.getBean("personService"); 
  7.     personService.save();