编码剖析Spring管理Bean的原理

在Spring的第一个案例中,我们已经知道了怎么将bean交给Spring容器进行管理,并且明白了怎么从Spring容器中获取bean。那我们就有一个疑问了:Spring是如何创建并管理bean的呢?现在我们就来编码剖析Spring管理Bean的原理。
本文是在Spring的第一个案例的基础上展开的。
我们要使用dom4j读取Sping的配置文件——beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"></bean>

</beans>

那么就需要将dom4j所需的jar包导入该项目中。dom4j所需的jar包为:

  • dom4j-1.6.1.jar
  • jaxen-1.1-beta-6.jar

dom4j读取到诸如

<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"></bean>

这样的内容时,务必需要将读取到的bean的信息存到一个JavaBean对象中。于是我们可在junit.test包下创建这样一个JavaBean——BeanDefinition.java,其代码为:

/**
 * 将读取到的bean的信息存到一个JavaBean对象中
 *
 */
public class BeanDefinition {
    private String id;
    private String className;

    public BeanDefinition(String id, String className) {
        this.id = id;
        this.className = className;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getClassName() {
        return className;
    }
    public void setClassName(String className) {
        this.className = className;
    }
}

接下来我们就创建一个传智播客版的Spring容器来模拟Spring容器。在junit.test下新建一个类——ItcastClassPathXMLApplicationContext.java,其代码如下:

/**
 * 传智播客版Spring容器
 *
 */
public class ItcastClassPathXMLApplicationContext {
    private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();
    private Map<String, Object> sigletons = new HashMap<String, Object>();

    public ItcastClassPathXMLApplicationContext(String filename) {
        this.readXML(filename);
        this.instanceBeans();
    }

    /**
     * 完成bean的实例化
     */
    private void instanceBeans() {
        for (BeanDefinition beanDefinition : beanDefines) {
            try {
                if (beanDefinition.getClassName() != null && !"".equals(beanDefinition.getClassName().trim())) {
                    sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 读取XML配置文件
     * @param filename
     */
    private void readXML(String filename) {
        SAXReader saxReader = new SAXReader();
        Document document = null;
        try {
            URL xmlpath = this.getClass().getClassLoader().getResource(filename);
            document = saxReader.read(xmlpath);
            Map<String, String> nsMap = new HashMap<String, String>();
            nsMap.put("ns", "http://www.springframework.org/schema/beans"); // 加入命名空间
            XPath xsub = document.createXPath("//ns:beans/ns:bean"); // 创建beans/bean查询路径
            xsub.setNamespaceURIs(nsMap); // 设置命名空间
            List<Element> beans = xsub.selectNodes(document); // 获取文档下所有bean节点
            for (Element element : beans) {
                String id = element.attributeValue("id"); // 获取id属性值
                String clazz = element.attributeValue("class"); // 获取class属性值
                BeanDefinition beanDefine = new BeanDefinition(id, clazz);
                beanDefines.add(beanDefine);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取bean实例
     * @param beanName
     * @return
     */
    public Object getBean(String beanName) {
        return this.sigletons.get(beanName);
    }
}

这样,传智播客版的Spring容器就创建出来了。接下来我们就要测试传智播客版的Spring容器是否能够取得bean实例,只须修改SpringTest类的代码为:

public class SpringTest {

    @Test
    public void test() {
        // ApplicationContext是接口
        // ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); // 实例化Spring容器
        // PersonService personService = (PersonService) ctx.getBean("personService"); // 从Spring容器取得bean
        // personService.save();

        ItcastClassPathXMLApplicationContext ctx = new ItcastClassPathXMLApplicationContext("beans.xml"); // 实例化Spring容器
        PersonService personService = (PersonService) ctx.getBean("personService"); // 从Spring容器取得bean
        personService.save();
    }

}

测试test()方法,Eclipse控制台打印如下:
这里写图片描述

通过编写代码剖析Spring管理Bean的原理,我们就能深刻理解Spring内部到底是如何创建并管理bean实例的.

 

posted @ 2018-06-05 21:55  bo客先生  阅读(229)  评论(0编辑  收藏  举报