自己动手写spring容器(2)

上篇我们自己写了一个很简单的spring容器,该容器只是做了简单的bean的实例化,并没有spring的核心之一的IOC(依赖注入),也叫做控制反转,这里我就不讲这个的具体含义,不知道的园友可以自行百度,百度上有很多介绍spring IOC的,在这里我们要实现的就是spring的IOC

首先,我们需要准备一个bean的配置文件,在上篇额配置文件基础上加入了Dao的内容,现在我们要做的就是service对Dao的依赖注入。

1   <bean id="personService" class="com.yangyang.service.impl.PersonServiceImpl">
2         <property name="personDao" ref="personDao"></property>
3         <property name="age" value="10"></property>
4     </bean>
5     <bean id="personDao" class="com.yangyang.dao.impl.PersonDaoImpl">
6     </bean>

 分析这个xml文件,知需要建立一个PropertyDefinition类,用来存储Property的属性,在此只列举了name,ref,value三个简单的属性,对集合类型的属性暂时没有做处理。

 1 package com.juit;
 2 
 3 /**
 4  * 属性模型
 5  * @author Administer
 6  *
 7  */
 8 public class PropertyDefinition {
 9 
10     /**
11      * 属性名称
12      */
13     private String name;
14     /**
15      * 属性引用值
16      */
17     private String ref;
18     
19     /**
20      * 属性value值
21      */
22     private String value;
23     public PropertyDefinition(String name, String ref,String value) {
24         this.name = name;
25         this.ref = ref;
26         this.value=value;
27     }
28     public String getName() {
29         return name;
30     }
31     public void setName(String name) {
32         this.name = name;
33     }
34     public String getRef() {
35         return ref;
36     }
37     public void setRef(String ref) {
38         this.ref = ref;
39     }
40     public String getValue() {
41         return value;
42     }
43     public void setValue(String value) {
44         this.value = value;
45     };
46 }

当然,由于property 在bean 的下面,因此需要在BeanDefinition中加入PropertyDefinition:

完整的BeanDefinition如下:

 1 package com.juit;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 /**
 7  * Bean对象
 8  * @author Administer
 9  *
10  */
11 public class BeanDefinition {
12 
13     private String id;//bean的id
14     private String className;//bean的类
15     private List<PropertyDefinition> propertyDefinitions=new ArrayList<PropertyDefinition>();//bean对象的属性
16     
17     public BeanDefinition(String id, String className) {
18         this.id = id;
19         this.className = className;
20     }
21     public String getId() {
22         return id;
23     }
24     public void setId(String id) {
25         this.id = id;
26     }
27     public String getClassName() {
28         return className;
29     }
30     public void setClassName(String className) {
31         this.className = className;
32     }
33     public List<PropertyDefinition> getPropertyDefinitions() {
34         return propertyDefinitions;
35     }
36     public void setPropertyDefinitions(List<PropertyDefinition> propertyDefinitions) {
37         this.propertyDefinitions = propertyDefinitions;
38     }
39 }

并在解析xml文件的地方加入对property的解析,完整的readXml如下:

 1 private void readXml2(String fileName) {
 2         //创建一个读取器
 3         SAXReader saxReader=new SAXReader();
 4         Document document=null;
 5         try {
 6             //获取要读取的配置文件的路径
 7             URL xmlPath=this.getClass().getClassLoader().getResource(fileName);
 8             //读取文件内容
 9             document=saxReader.read(xmlPath);
10             //获取xml中的根元素
11             Element rootElement=document.getRootElement();
12             for (Iterator iterator = rootElement.elementIterator(); iterator.hasNext();) {
13                 Element element = (Element) iterator.next();
14                 String id=element.attributeValue("id");//获取bean的id属性值
15                 String clazz=element.attributeValue("class");//获取bean的class属性值
16                 BeanDefinition beanDefinition=new BeanDefinition(id,clazz);
17                 //获取bean的Property属性
18                 for (Iterator subElementIterator = element.elementIterator(); subElementIterator.hasNext();) {
19                     Element subElement = (Element) subElementIterator.next();
20                     String propertyName=subElement.attributeValue("name");
21                     String propertyRef= subElement.attributeValue("ref");
22                     String propertyValue=subElement.attributeValue("value");
23                     PropertyDefinition propertyDefinition=new PropertyDefinition(propertyName, propertyRef,propertyValue);
24                     beanDefinition.getPropertyDefinitions().add(propertyDefinition);
25                 }
26                 beanDefines.add(beanDefinition);
27             }
28         } catch (Exception e) {
29             e.printStackTrace();
30         }
31     }
接下来就要来实现关键的对依赖对象的注入功能的逻辑了。
1 public YhdClassPathXmlApplicationContext(String fileName){
2         
3         //1.读取spring的配置文件
4             this.readXml(fileName);
5         //2.实例化bean
6         this.instanceBeans();
7         //3.实现对依赖对象的注入功能
8         this.injectObject();
9     }    

下面来完成injectObject这个功能:

 1 /**
 2      * 为bean对象的属性注入值
 3      * 
 4      * Administer
 5      * 2013-8-18 下午7:59:03
 6      */
 7     private void injectObject() {
 8         //遍历配置文件中定义的所有的bean
 9         for (BeanDefinition beanDefinition : beanDefines) {
10             //找到要注入的bean
11             Object bean=sigletons.get(beanDefinition.getId());
12             if (bean != null) {
13                 try {
14                     BeanInfo info = Introspector.getBeanInfo(bean.getClass());//通过类Introspector的getBeanInfo方法获取对象的BeanInfo 信息
15                     //通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后我们就可以通过反射机制来调用这些方法。
16                     PropertyDescriptor[] pds = info.getPropertyDescriptors();//获得 bean所有的属性描述
17                     //遍历要注入的bean的所有属性
18                     for (PropertyDefinition propertyDefinition : beanDefinition.getPropertyDefinitions()) {
19                         //遍历要注入bean通过属性描述器得到的所有属性以及行为
20                         for (PropertyDescriptor propertyDescriptor : pds) {
21                             //用户定义的bean属性与java内省后的bean属性名称相同时
22                             if (propertyDefinition.getName().equals(propertyDescriptor.getName())) {
23                                 Method setter=propertyDescriptor.getWriteMethod();//获取属性的setter方法
24                                 //取到了setter方法
25                                 if (setter != null) {
26                                     Object value=null;//用来存储引用的值
27                                     if (propertyDefinition.getRef() != null && !propertyDefinition.getRef().equals("")) {
28                                         value=sigletons.get(propertyDefinition.getRef());//获取引用的对象的值
29                                     }else {
30                                         //ConvertUtil依赖两个jar包,一个是common-beanutils,而common-beanutils又依赖common-logging
31                                         //ConvertUtil将任意类型转化为需要的类型
32                                         value=ConvertUtils.convert(propertyDefinition.getValue(), propertyDescriptor.getPropertyType());
33                                     }
34                                     setter.setAccessible(true);//保证setter方法可以访问私有
35                                     try {
36                                         setter.invoke(bean, value);//把引用对象注入到属性
37                                     } catch (Exception e) {
38                                         e.printStackTrace();
39                                     }
40                                 }
41                                 break;//找到了注入的属性后,跳出循环
42                             }
43                         }
44                     }
45                 } catch (IntrospectionException e) {
46                     e.printStackTrace();
47                 }
48             }
49         }
50     }

这里用到了commons-beanutils-core-1.8.3.jar、commons-logging-1.1.1.jar这两个jar,大家可以到apache的网站上进行下载,主要是用到了ConvertUtils.convert将任意类型转化为需要的类型的方法。

其实依赖注入的思想也很简单,它是通过反射机制实现的。

最后还剩下一步测试,同理

1     @Test
2     public void testInstanceSping() {
3         YhdClassPathXmlApplicationContext ctx=new YhdClassPathXmlApplicationContext("resources/beans.xml");
4         PersonService personService=(PersonService)ctx.getBean("personService");
5         personService.savePerson();
6     }

personService接口代码:

1 package com.yangyang.service;
2 
3 public interface PersonService {
4     public void savePerson();
5 
6 }

PersonServiceImpl实现的代码:

 1 package com.yangyang.service.impl;
 2 
 3 import com.yangyang.dao.PersonDao;
 4 import com.yangyang.service.PersonService;
 5 
 6 public class PersonServiceImpl implements PersonService{
 7     private PersonDao personDao;
 8     private Integer age;
 9     
10     public PersonDao getPersonDao() {
11         return personDao;
12     }
13     
14     public void setPersonDao(PersonDao personDao) {
15         this.personDao = personDao;
16     }
17 
18     public Integer getAge() {
19         return age;
20     }
21 
22     public void setAge(Integer age) {
23         this.age = age;
24     }
25 
26     @Override
27     public void savePerson() {
28         System.out.println("age:"+age);
29         System.out.println("service中的save方法调用成功");
30         personDao.savePerson();
31     }
32 
33 }

在控制台上我们可以看到:

age:10

service中的save方法调用成功

好,这样依赖注入就完成了,下篇就要来实现比这个稍微复杂的注解的依赖注入的实现,敬请期待。。。

 

posted @ 2013-08-27 23:18  静静的码农  阅读(2238)  评论(7编辑  收藏  举报