前言
Spirng中ApplicationContext和BeanFactory道理有什么区别,可以先看看官方文档是如何解释的。
The org.springframework.beans and org.springframework.context packages are the
basis for Spring Framework’s IoC container. The BeanFactory interface provides
an advanced configuration mechanism capable of managing any type of object.
ApplicationContext is a sub-interface of BeanFactory. It adds:
Easier integration with Spring’s AOP features
Message resource handling (for use in internationalization)
Event publication
Application-layer specific contexts such as the WebApplicationContext for use
in web applications.
文档中表达的意思就是ApplicationContext在BeanFactory基础上添加了很多的功能,但是对这两个接口的理解还是不够深刻,于是我打算看一看SpringBoot中是如何使用这两个接口的。
ApplicationContext
ApplicationContext的初始化
一切都要从SpringBoot的启动开始说起,在SpringBoot启动的时候会更具应用类型创建不同的上下文:
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
如果是SERVLET则会创建AnnotationConfigServletWebServerApplicationContext类型的上下文(本文也是讨论改种类型)。
AnnotationConfigServletWebServerApplicationContext类Diagram图
AbstractApplicationContext
AbstractApplicationContext实现了ConfigurableApplicationContext接口。
/**
* SPI interface to be implemented by most if not all application contexts.
* Provides facilities to configure an application context in addition
* to the application context client methods in the
* {@link org.springframework.context.ApplicationContext} interface.
*
* <p>Configuration and lifecycle methods are encapsulated here to avoid
* making them obvious to ApplicationContext client code. The present
* methods should only be used by startup and shutdown code.
*/
该接口提供对应用上下文配置能力。该接口中有又一个比较重要的方法org.springframework.context.ConfigurableApplicationContext#refresh,在AbstractApplicationContext抽象类中的实现方法如下:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
refresh()方法会在org.springframework.boot.SpringApplication#refresh方法中调用
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
refresh()方法文档中解释说明在执行了该方法后,所有的singleton都会被实例化。
GenericApplicationContext
/**
* Generic ApplicationContext implementation that holds a single internal
* {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
* instance and does not assume a specific bean definition format. Implements
* the {@link org.springframework.beans.factory.support.BeanDefinitionRegistry}
* interface in order to allow for applying any bean definition readers to it.
*/
GenericApplicationContext持有了DefaultListableBeanFactory实例,并实现了BeanDefinitionRegistry接口提供了对BeanDefinition增、删、查功能。
GenericApplicationContext.java
private final DefaultListableBeanFactory beanFactory;
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
从GenericApplicationContext的构造函数中初始化了DefaultListableBeanFactory, 对BeanDefinition增、删、查的功能都委托给了DefaultListableBeanFactory对象实现。其实在AbstractApplicationContext中实现了对bean的查找能力
AbstractApplicationContext.java
@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
但是genBeanFactory()在AbstractApplicationContext中是一个抽象方法,GenericApplicationContext实现了该方法
GenericApplicationContext.java
@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
return this.beanFactory;
}
我们经常在写Spring测试代码的时候都都会对一个Bean进行查找如下:
public class CdtftApplication {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext("github.cdtft");
MyTestBean myTestBean = (MyTestBean) context.getBean("myTestBean");
System.out.println(myTestBean);
}
}
背后真正提供这种查找能力的是DefaultListableBeanFactory。