zoukankan      html  css  js  c++  java
  • SpringIOC容器——ApplicationContext和BeanFactory

    本篇博客将从源码的角度讨论ApplicationContext与BeanFactory的关系。

    提到ApplicationContext与BeanFactory的区别,我们都知道一下几点:

    • BeanFactory:

    是Spring里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能。

    • ApplicationContext:

    应用上下文,继承BeanFactory接口,它是Spring的一各更高级的容器,提供了更多的有用的功能;

    1. 国际化(MessageSource)

    2. 访问资源,如URL和文件(ResourceLoader)

    3. 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层

    4. 消息发送、响应机制(ApplicationEventPublisher)

    5. AOP(拦截器)

    但是其内部究竟是怎么实现的,这两个类究竟是什么关系呢?我们先运行一个demo。

    public class Repository {
    
        private ObjectFactory<ApplicationContext> objectFactory;
    
        private BeanFactory beanFactory;
    
        public ObjectFactory<ApplicationContext> getObjectFactory() {
            return objectFactory;
        }
    
        public void setObjectFactory(ObjectFactory<ApplicationContext> objectFactory) {
            this.objectFactory = objectFactory;
        }
    
        public BeanFactory getBeanFactory() {
            return beanFactory;
        }
    
        public void setBeanFactory(BeanFactory beanFactory) {
            this.beanFactory = beanFactory;
        }
    }
    
    public class DependencyIngectionDemo {
    
        public static void main(String[] args) {
            
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("META-INF/dependency-ingection-context.xml");
            //自定义的Bean
            Repository repository = applicationContext.getBean(Repository.class);
            //内部依赖的Bean
            repository.getBeanFactory();
            System.out.println(repository.getObjectFactory().getObject() == applicationContext);
            System.out.println(repository.getBeanFactory() == applicationContext);
            System.out.println(repository.getObjectFactory().getObject());
            System.out.println(repository.getBeanFactory());
        }
    }
    

    我们自定义一个名为Repository的类,其中有两个属性分别为objectFactory、beanFactory,objectFactory的泛型为ApplicationContext,运行main函数得到以下结果:

    true
    false
    org.springframework.context.support.ClassPathXmlApplicationContext@238e0d81, started on Sun Aug 30 18:48:39 CST 2020
    org.springframework.beans.factory.support.DefaultListableBeanFactory@2d554825
    

    首先我们比较了repository内部的objectFactory和当前容器的applicationContext发现是相同的对象,接下来我们比较repository内部的beanFactory和当前容器的applicationContext返回false,我们将repository.getObjectFactory().getObject()打印出来,发现repository.getObjectFactory().getObject()对象类型为ClassPathXmlApplicationContext,而repository.getBeanFactory()对象类型为DefaultListableBeanFactory,同时也说明当前容器applicationContext类型为ClassPathXmlApplicationContext,我们追溯一下源码看看为什么会产生这种结果。

    容器applicationContext通过构造ClassPathXmlApplicationContext对象获得,根据这个类向上追溯,得到这样条继承关系:

    ClassPathXmlApplicationContext <- AbstractXmlApplicationContext <- AbstractRefreshableConfigApplicationContext <- AbstractRefreshableApplicationContext <- AbstractApplicationContext <- ConfigurableApplicationContext <- ApplicationContext <- ListableBeanFactory <- BeanFactory

    在ConfigurableApplicationContext类中我们发现定义了getBeanFactory()方法,但实际上AbstractApplicationContext就是BeanFactory的子类,为什么要这样做呢,我们继续追溯可以找到AbstractRefreshableApplicationContext实现了getBeanFactory()方法,实现如下:

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

    我们发现AbstractRefreshableApplicationContext和beanFactory实际上是一个组合关系,而不是完全的继承关系而beanFactory属性的类型为DefaultListableBeanFactory这说明了我们上面的demo中repository内部依赖的beanFactory类型为DefaultListableBeanFactory。

    我们再看一下AbstractApplicationContext中的getBean()方法:

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

    发现是通过调用内部组合的beanFactory的方法而不是实现父类,这种方式有点类似于代理。

    总结:

    ApplicationContext是BeanFactory的子接口,说明ApplicationContext is BeanFactory。并且ApplicationContext 是BeanFactory的包装类,也就是内部组合了BeanFactory的实现-DefaultListableBeanFactory。为什么包装了DefaultListableBeanFactory,因为它需要简化且丰富功能来为企业开发提供更高的便捷性,也就是说ApplicationContext 是DefaultListableBeanFactory的超集。
    至于为什么UserRepository注入的BeanFactory 不等于ClassPathXmlApplicationContext得到的BeanFactory ,是因为AbstractApplicationContext#prepareBeanFactory中 指明了 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); 也就是说当byType是BeanFactory.class的时候,获得是的ApplicationContext中的DefaultListableBeanFactory对象。
    那真正的IOC的底层实现就是BeanFactory的实现类,因为ApplicationContext是委托DefaultListableBeanFactory来操作getBean等方法的。

  • 相关阅读:
    JAVA中对null进行强制类型转换
    git 初次push
    svn还原与本地版本回退
    后台用map接收数据,报类型转换错误
    eclipse从svn导入静态文件
    APP项目下载及运行
    Yii2中如何使用CodeCeption
    开发资源整合
    工作流设计参考(包括PHP实现)
    PHP单元测试利器:PHPUNIT初探
  • 原文地址:https://www.cnblogs.com/youtang/p/13590780.html
Copyright © 2011-2022 走看看