BeanFactory 和 ApplicationContext

从一个示例开始,先自定义一个类:

package top.callback.demo.bean;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.ApplicationContext;

public class User {
  private BeanFactory beanFactory;
  private ObjectFactory<ApplicationContext> objectFactory;
  
  // getter & setter
}

配置文件:

<bean id="user" class="top.callback.demo.bean.User" autowire="byType" />

测试程序:

public static void main(String[] args) {
  BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/application-context.xml");
  User user = beanFactory.getBean(User.class);
  BeanFactory innerBeanFactory = user.getBeanFactory();
  ObjectFactory<ApplicationContext> applicationContext = user.getObjectFactory().getObject();
  
  System.out.println(beanFactory == innerBeanFactory); // false
  System.out.println(beanFactory == applicationContext); // true
}

为什么 beanFactory 不等于 innerBeanFactory,而等于 applicationContext

按理说,User 对象是从 beanFactory 获取的,那么 user#beanFactory 和 beanFactory 应该是一个东西,但实际上却是爹生了娃,但亲子鉴定说娃不是亲生的。这时候就要从 ClassPathXmlApplicationContext 入手,去看看他的继承关系是什么样的。

如果图片看不清楚,可以自行在 IDEA 里面借助 Diagrms 功能进行查看。从图中可以看到,ClassPathXmlApplicationContext 一路火花带闪电的层层继承,最终成为了 BeanFactory 接口的一个间接实现。所以代码里可以使用多态将 ClassPathXmlApplicationContext 的实例赋值给 BeanFactory。

在继承链中有一个抽象类 AbstractApplicationContext,其中重载了多个 getBean() 方法用于获取容器内的 Bean。而这些方法无一例外的都调用了 getBeanFactory() 来先获取一个 BeanFactory 实例,进而调用 BeanFactory 的 getBean() 方法实际执行 Bean 获取。

意外的是,这个类里的 getBeanFactory() 方法是个抽象方法。查看其返回值 ConfigurableListableBeanFactory 接口的实现,发现无论哪个实现都是返回自身的 beanFactory 字段,而这个字段的类型都是 DefaultListableBeanFactory。

同时,在 AbstractApplicationContext 的 prepareBeanFactory() 中也明确指定了要使用的 BeanFactory 实现是通过 getBeanFactory() 方法返回的 DefaultListableBeanFactory。

beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); // AbstractApplicationContext 663行

回到最初的示例,配置文件里指定了以 byType 类型注入的形式进行注入,那么根据上述分析,user#beanFactory 注入的就一定是 DefaultListableBeanFactory。而通过配置文件创建的是 ClassPathXmlApplicationContext 的实例,这两个对象自然就不相等了。

至于示例中的 beanFactory 等于 applicationContext,这是因为在这个示例程序运行过程中,只有一个 ClassPathXmlApplicationContext 是 ApplicationContext 接口的实现,所以按类型注入下两者其实就是同一个对象。

结合上面的继承关系图可以看出,ClassPathXmlApplicationContext 实际上是 BeanFactory 接口的一个最终实现。在其继承链上,BeanFactory 被从 ApplicationContext 接口开始的多个类进行了功能丰富,并且对 BeanFactory 的基础功能进行了代理。官方文档这么描述 BeanFactory 和 ApplicationContext 的关系:

In short, the BeanFactory provides the configuration framework and basic functionality, and the ApplicationContext adds more enterprise-specific functionality. The ApplicationContext is a complete superset of the BeanFactory and is used exclusively in this chapter in descriptions of Spring’s IoC container.

ApplicationContext 是 BeanFactory 的超集,BeanFactory 仅提供基础功能和配置,ApplicationContext 在其上面增加了更多企业性功能。可以简单的理解为,BeanFactory 是给 Spring 框架自身用的,而 ApplicationContext 是给 Spring 框架的使用者用的。

原文地址:https://www.cnblogs.com/zidu/p/spring-beanfactory-application-context.html