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等方法的。

原文地址:https://www.cnblogs.com/youtang/p/13590780.html