• spring源码系列01BeanFactory和ApplicationContext的关系


    spring源码系列01-BeanFactory和ApplicationContext的关系

    平时经常遇到的一个问题就是问BeanFactoryApplicationContext这两种容器的区别,这篇文章从另一个角度,这两种容器之间的关系来谈起,对这两种容器进行一个介绍和对比。

    先说结论: ApplicationContext类型容器的内部维护了一个BeanFactory类型的容器,bean都是存在这个内部BeanFactory里的

    当然,这两个都是接口,真正使用的容器是它们的实现类

    一、从类图开始

    首先来看一下类图

    BeanFactory和ApplicationContext的类图
    从上边的类图上我们可以看出这几个要点:

    (1) ApplicationContextBeanFactory的子接口,所以BeanFactory的功能ApplicationContext都有

    (2) ApplicationContext 又实现了几个接口,这每一个接口都代表一种功能,而这些功能是BeanFactory类型容器没有的。比如ApplicationEventPublisher这个接口,给spring容器提供了以类似发布订阅的形式进行事件处理的功能;EnvironmentCapable 接口给spring容器提供了获取环境变量的能力;MessageSource接口给spring容器提供了国际化处理的能力。

    二、一段spring入门代码

    在这里我们先使用一下ApplicationContext容器,来引出这两种容器之间的关系。我们演示下如何以xml的形式来使用spring,使用的容器是ClassPathXmlApplicationContext这个ApplicationContext的实现类。

    配置文件

    <?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="person" class="com.lyy.vo.Person"></bean>
    </beans>
    

    java代码

    public class Test01 {
        public static void main(String[] args) {
            ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
            Person person = app.getBean(Person.class);
            System.out.println(person);
        }
    }
    

    上边的一段代码,是我们学习spring时常写的一段代码,其中app是创建出来的容器实例,通过它可以获取我们需要的Bean。那么我们提出一个问题,ApplicationContext类型的容器中具体的Bean是在哪里存储的?

    要回答这个问题,我们可以跟一下app.getBean(Person.class)方法,它是从哪里取的值,那Bean就是存在哪里的。

    三、ApplicationContext容器中如何存储Bean的探索

    先给出ClassPathXmlApplicationContext的类图,方便后边的讲解。

    首先,点进去app.getBean方法,来到AbstractApplicationContext.getBean()

    @Override
    	public <T> T getBean(Class<T> requiredType) throws BeansException {
    		assertBeanFactoryActive();
    		return getBeanFactory().getBean(requiredType);
    	}
    

    从这个方法最后一句的getBeanFactory(),我们可以猜测,ClassPathXmlApplicationContext容器内部有一个

    BeanFactory容器,Bean都是存在这个里边的。继续跟进getBeanFactory()方法,发现这个方法是定义在

    AbstractApplicationContext中的一个抽象方法,针对xml方式使用,具体的实现是在

    AbstractRefreshableApplicationContext中,这里要结合上边的类图看,会更好理解。

    @Override
    	public final ConfigurableListableBeanFactory getBeanFactory() {
    		DefaultListableBeanFactory beanFactory = this.beanFactory;
    		if (beanFactory == null) {
    			throw new IllegalStateException
                    ("BeanFactory not initialized or already closed - " +
    					"call 'refresh' before accessing beans via the ApplicationContext");
    		}
    		return beanFactory;
    	}
    

    从这段代码看,返回的这个BeanFactory确实是AbstractRefreshableApplicationContext中的一个属性,这就验证了我们上边的猜想,ApplicationContext类型容器的内部维护了一个BeanFactory类型的容器

    针对ClassPathXmlApplicationContext,这个BeanFactory是维护在它的父类当中的

    再去看下这个属性的类型

    /** Bean factory for this context. */
    	@Nullable
    	private volatile DefaultListableBeanFactory beanFactory;
    

    这是AbstractRefreshableApplicationContext类中定义属性的地方,这里的注释也侧面验证了上边的猜想。

    DefaultListableBeanFactory这个BeanFactory的实现类,才是真正的存储springBean的。

    四、总结

    通过上边的分析,我们得到了一个重要的结论:ApplicationContext类型容器的内部维护了一个BeanFactory类型的容器,bean都是存在这个内部BeanFactory里的。这就是这两种容器之间的关系。

    至于区别,除了上边给出的 ApplicationContext多了事件处理,环境变量,国际化处理外,还有很重要的一点,

    BeanFactory类型的容器中的Bean是懒加载的,获取的时候才会创建,而ApplicationContext中的bean,容器启动完成后就已经创建好了,这个在后边的文章中会具体分析。

    本文已同步发表在我的个人公众号java开发实战,欢迎大家关注

  • 相关阅读:
    IIs安装&发布&解决遇到的问题
    Silverlight RadChart :创建十字定位&圈选
    桌面小工具,网络时间表
    毕设之c#多线程学习(官方+转载)
    常用的sql语言基础(1)
    转:C# DataGridView控件清空数据出错解决方法
    转:DataTable的Compute方法的应用
    转:判断DATASET是否为空
    转:DataSet、DataTable、DataRow、DataColumn区别及使用实例
    转发:C#加密方法汇总
  • 原文地址:https://www.cnblogs.com/chengxuxiaoyuan/p/16240451.html
Copyright © 2020-2023  润新知