前言
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
。