• 自己动手写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方法调用成功

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

    ----------------------------------------------------------------------------------------
    如果您觉得阅读本文对您有帮助,请微信扫码关注作者,与我进行交流!欢迎各位转载,转载文章之后须在文章页面明显位置给出作者和原文连接,谢谢。
  • 相关阅读:
    转物理老师的说说,过好自己的生活,别人的梦幻生活背后也有你看不见的无奈
    第一、二、三、BC范式的学习总结
    一位毕业四年的前辈的经历
    普里姆算法,克鲁斯卡尔算法,迪杰斯特拉算法,弗洛里德算法
    从零开始构建JavaScript框架4——DOM遍历2
    从零开始构建JavaScript框架3——DOM遍历1
    从零开始构建JavaScript框架2——总体结构以及元素的获取和创建
    从零开始构建JavaScript框架1——为何JavaScript开发需要框架
    从浏览器输入URL到页面加载完成到底发生了什么?
    第5课 C语言指针深入1
  • 原文地址:https://www.cnblogs.com/shunyang/p/3286167.html
Copyright © 2020-2023  润新知