从一个示例开始,先自定义一个类:
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 theApplicationContext
adds more enterprise-specific functionality. TheApplicationContext
is a complete superset of theBeanFactory
and is used exclusively in this chapter in descriptions of Spring’s IoC container.
ApplicationContext 是 BeanFactory 的超集,BeanFactory 仅提供基础功能和配置,ApplicationContext 在其上面增加了更多企业性功能。可以简单的理解为,BeanFactory 是给 Spring 框架自身用的,而 ApplicationContext 是给 Spring 框架的使用者用的。