自己動手寫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方法調用成功

好,這樣依賴注入就完成了,下篇就要來實現比這個稍微復雜的注解的依賴注入的實現,敬請期待。。。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM