本篇博客将从源码的角度讨论ApplicationContext与BeanFactory的关系。
提到ApplicationContext与BeanFactory的区别,我们都知道一下几点:
- BeanFactory:
是Spring里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能。
- ApplicationContext:
应用上下文,继承BeanFactory接口,它是Spring的一各更高级的容器,提供了更多的有用的功能;
-
国际化(MessageSource)
-
访问资源,如URL和文件(ResourceLoader)
-
载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
-
消息发送、响应机制(ApplicationEventPublisher)
-
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等方法的。