code-learning/springboot/10-Spring Boot 源码分析-ServletWebServerApplicationContext.md

794 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 精尽 Spring Boot 源码分析 —— ServletWebServerApplicationContext
# 1. 概述
在 [《精尽 Spring Boot 源码分析 —— SpringApplication》](http://svip.iocoder.cn/Spring-Boot/SpringApplication/) 一文中,我们看到 `SpringApplication#createApplicationContext()` 方法,根据不同的 Web 应用类型,创建不同的 Spring 容器。代码如下:
```
// SpringApplication.java
/**
* The class name of application context that will be used by default for non-web
* environments.
*/
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ "annotation.AnnotationConfigApplicationContext";
/**
* The class name of application context that will be used by default for web
* environments.
*/
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
/**
* The class name of application context that will be used by default for reactive web
* environments.
*/
public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
protected ConfigurableApplicationContext createApplicationContext() {
// 根据 webApplicationType 类型,获得 ApplicationContext 类型
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);
}
}
// 创建 ApplicationContext 对象
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
```
- 本文,我们要分享的就是,`SERVLET` 类型对应的 Spring 容器类型 **AnnotationConfigServletWebServerApplicationContext** 类。
AnnotationConfigServletWebServerApplicationContext 的类图关系如下:[![类图](10-Spring Boot 源码分析-ServletWebServerApplicationContext.assets/01.jpg)](http://static.iocoder.cn/images/Spring-Boot/2021-01-16/01.jpg)类图
- 本文,我们只重点看 ServletWebServerApplicationContext 和 AnnotationConfigServletWebServerApplicationContext 类。
- 为了阅读的友好性,艿艿希望胖友阅读过 [《精尽 Spring MVC 源码分析 —— 容器的初始化(三)之 Servlet 3.0 集成》](http://svip.iocoder.cn/Spring-MVC/context-init-integration-with-Servlet-3.0/) 和 [《精尽 Spring MVC 源码分析 —— 容器的初始化(四)之 Spring Boot 集成》](http://svip.iocoder.cn/Spring-MVC/context-init-integration-with-SpringBoot/) 两文。
> 艿艿:厚着脸皮说,上面两篇文章提到的内容,基本就不再赘述。
> 旁白君:真不要脸!
# 2. ServletWebServerApplicationContext
`org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext` ,实现 ConfigurableWebServerApplicationContext 接口,继承 GenericWebApplicationContext 类Spring Boot 使用 Servlet Web 服务器的 ApplicationContext 实现类。
- `org.springframework.boot.web.servlet.context.ConfigurableWebServerApplicationContext` 接口,实现它后,可以获得管理 WebServer 的能力。代码如下:
```
// ConfigurableWebServerApplicationContext.java
public interface ConfigurableWebServerApplicationContext extends ConfigurableApplicationContext, WebServerApplicationContext {
/**
* Set the server namespace of the context.
* @param serverNamespace the server namespace
* @see #getServerNamespace()
*/
void setServerNamespace(String serverNamespace);
}
```
- [`org.springframework.context.ConfigurableApplicationContext`](https://github.com/YunaiV/spring-framework/blob/master/spring-context/src/main/java/org/springframework/context/ConfigurableApplicationContext.java) ,是 Spring Framework 提供的类,就不细看了。
- `org.springframework.boot.web.context.WebServerApplicationContext` ,继承 ApplicationContext 接口WebServer ApplicationContext 接口。代码如下:
```
// WebServerApplicationContext.java
public interface WebServerApplicationContext extends ApplicationContext {
/**
* Returns the {@link WebServer} that was created by the context or {@code null} if
* the server has not yet been created.
* @return the web server
*/
WebServer getWebServer();
/**
* Returns the namespace of the web server application context or {@code null} if no
* namespace has been set. Used for disambiguation when multiple web servers are
* running in the same application (for example a management context running on a
* different port).
* @return the server namespace
*/
String getServerNamespace();
}
```
- 重点是,可以获得 WebServer 的方法。😈 因为获得它,可以做各种 WebServer 的管理。
- [`org.springframework.web.context.support.GenericWebApplicationContext`](https://github.com/YunaiV/spring-framework/blob/master/spring-web/src/main/java/org/springframework/web/context/support/GenericWebApplicationContext.java) ,是 Spring Framework 提供的类,就不细看啦。
## 2.1 构造方法
```
// ServletWebServerApplicationContext.java
/**
* Constant value for the DispatcherServlet bean name. A Servlet bean with this name
* is deemed to be the "main" servlet and is automatically given a mapping of "/" by
* default. To change the default behavior you can use a
* {@link ServletRegistrationBean} or a different bean name.
*/
public static final String DISPATCHER_SERVLET_NAME = "dispatcherServlet";
/**
* Spring WebServer 对象
*/
private volatile WebServer webServer;
/**
* Servlet ServletConfig 对象
*/
private ServletConfig servletConfig;
/**
* 通过 {@link #setServerNamespace(String)} 注入。
*
* 不过貌似,一直没被注入过,可以暂时先无视
*/
private String serverNamespace;
public ServletWebServerApplicationContext() {
}
public ServletWebServerApplicationContext(DefaultListableBeanFactory beanFactory) {
super(beanFactory);
}
```
- 简单看看即可。
因为后续的逻辑,涉及到 Spring 容器的初始化的生命周期,所以我们来简单看看 `AbstractApplicationContext#refresh()` 的方法。代码如下:
```
// AbstractApplicationContext.java
// `#refresh()` 方法
// ... 简化版代码
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory); // <1>
// 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(); // <2>
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh(); // <3>
```
- 这个方法,会被覆写。具体可以看 [「2.2 refresh」](https://svip.iocoder.cn/Spring-Boot/ServletWebServerApplicationContext/#) 小节。但是,即使覆写了,还是会调用该方法。
- `<1>` 处,调用 `#postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)` 方法,具体可以看 [「2.3 postProcessBeanFactory」](https://svip.iocoder.cn/Spring-Boot/ServletWebServerApplicationContext/#) 小节。
> 对 Spring BeanFactoryPostProcessor 的机制,可以看看 [《【死磕 Spring】—— IoC 之深入分析 BeanFactoryPostProcessor》](http://svip.iocoder.cn/Spring/IoC-BeanFactoryPostProcessor)
- `<2>` 处,调用 `#onRefresh()` 方法,具体可以看 [「2.4 onRefresh」](https://svip.iocoder.cn/Spring-Boot/ServletWebServerApplicationContext/#) 小节。
- `<3>` 处,调用 `#finishRefresh()` 方法,具体可以看 [「2.5 finishRefresh」](https://svip.iocoder.cn/Spring-Boot/ServletWebServerApplicationContext/#) 小节。
## 2.2 refresh
覆写 `#refresh()` 方法,初始化 Spring 容器。代码如下:
```
// ServletWebServerApplicationContext.java
@Override
public final void refresh() throws BeansException, IllegalStateException {
try {
super.refresh();
} catch (RuntimeException ex) {
// <X> 如果发生异常,停止 WebServer
stopAndReleaseWebServer();
throw ex;
}
}
```
- 主要是 `<X>` 处,如果发生异常,则调用 `#stopAndReleaseWebServer()` 方法,停止 WebServer。详细解析见 [「2.2.1 stopAndReleaseWebServer」](https://svip.iocoder.cn/Spring-Boot/ServletWebServerApplicationContext/#) 。
### 2.2.1 stopAndReleaseWebServer
`#stopAndReleaseWebServer()` 方法,停止 WebServer。代码如下
```
// ServletWebServerApplicationContext.java
private void stopAndReleaseWebServer() {
// 获得 WebServer 对象,避免被多线程修改了
WebServer webServer = this.webServer;
if (webServer != null) {
try {
// 停止 WebServer 对象
webServer.stop();
// 置空 webServer
this.webServer = null;
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
}
```
## 2.3 postProcessBeanFactory
覆写 `#postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)` 方法,代码如下:
```
// ServletWebServerApplicationContext.java
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// <1.1> 注册 WebApplicationContextServletContextAwareProcessor
beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
// <1.2> 忽略 ServletContextAware 接口。
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
// <2> 注册 ExistingWebApplicationScopes
registerWebApplicationScopes();
}
```
- `<1.1>` 处,注册 WebApplicationContextServletContextAwareProcessor 。WebApplicationContextServletContextAwareProcessor 的作用,主要是处理实现 ServletContextAware 接口的 Bean 。在这个处理类,初始化这个 Bean 中的 ServletContext 属性,这样在实现 ServletContextAware 接口的 Bean 中就可以拿到 ServletContext 对象了Spring 中 Aware 接口就是这样实现的。代码如下:
```
// WebApplicationContextServletContextAwareProcessor.java
public class WebApplicationContextServletContextAwareProcessor extends ServletContextAwareProcessor {
private final ConfigurableWebApplicationContext webApplicationContext;
public WebApplicationContextServletContextAwareProcessor(ConfigurableWebApplicationContext webApplicationContext) {
Assert.notNull(webApplicationContext, "WebApplicationContext must not be null");
this.webApplicationContext = webApplicationContext;
}
@Override
protected ServletContext getServletContext() {
ServletContext servletContext = this.webApplicationContext.getServletContext();
return (servletContext != null) ? servletContext : super.getServletContext();
}
@Override
protected ServletConfig getServletConfig() {
ServletConfig servletConfig = this.webApplicationContext.getServletConfig();
return (servletConfig != null) ? servletConfig : super.getServletConfig();
}
}
```
- 这样,就可以从 `webApplicationContext` 中,获得 ServletContext 和 ServletConfig 属性。
- `<1.2>` 处,忽略 ServletContextAware 接口,因为实现 ServletContextAware 接口的 Bean 在 `<1.1>` 中的 WebApplicationContextServletContextAwareProcessor 中已经处理了。
- 关于 `<1.1>` 和 `<1.2>` 处的说明,参考 [《Spring Boot 源码3 —— refresh ApplicationContext》](https://www.jianshu.com/p/58974c12cd6a) 文章。
> 艿艿:当读源码碰到困难时,也要善用搜索引擎,去寻找答案。😈 毕竟,有时候脑子不一定能快速想的明白。哈哈哈哈~
- `<2>` 处,调用 `#registerWebApplicationScopes()` 方法,注册 ExistingWebApplicationScopes 。代码如下:
```
// ServletWebServerApplicationContext.java
private void registerWebApplicationScopes() {
// 创建 ExistingWebApplicationScopes 对象
ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(getBeanFactory());
// 注册 ExistingWebApplicationScopes 到 WebApplicationContext 中
WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());
// 恢复
existingScopes.restore();
}
```
- 可以先不细研究~
## 2.4 onRefresh
覆写 `#onRefresh()` 方法,在容器初始化时,完成 WebServer 的创建(不包括启动)。代码如下:
```
// ServletWebServerApplicationContext.java
@Override
protected void onRefresh() {
// <1> 调用父方法
super.onRefresh();
try {
// 创建 WebServer
createWebServer();
} catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
```
- `<1>` 处,调用父 `#onRefresh()` 方法,执行父逻辑。这块,暂时不用了解。
- `<2>` 处,调用 `#createWebServer()` 方法,创建 WebServer 对象。详细解析,见 [「2.4.1 createWebServer」](https://svip.iocoder.cn/Spring-Boot/ServletWebServerApplicationContext/#) 。
### 2.4.1 createWebServer
`#createWebServer()` 方法,创建 WebServer 对象。
```
// ServletWebServerApplicationContext.java
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
// <1> 如果 webServer 为空,说明未初始化
if (webServer == null && servletContext == null) {
// <1.1> 获得 ServletWebServerFactory 对象
ServletWebServerFactory factory = getWebServerFactory();
// <1.2> 获得 ServletContextInitializer 对象
// <1.3> 创建(获得) WebServer 对象
this.webServer = factory.getWebServer(getSelfInitializer());
// TODO 1002 芋艿这个情况是?
} else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
} catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
// <3> 初始化 PropertySource
initPropertySources();
}
```
- `<1>` 处,如果 webServer 为空,说明未初始化。
- `<1.1>` 处,调用 `#getWebServerFactory()` 方法,获得 ServletWebServerFactory 对象。代码如下:
```
// ServletWebServerApplicationContext.java
protected ServletWebServerFactory getWebServerFactory() {
// Use bean names so that we don't consider the hierarchy
// 获得 ServletWebServerFactory 类型对应的 Bean 的名字们
String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
// 如果是 0 个,抛出 ApplicationContextException 异常,因为至少要一个
if (beanNames.length == 0) {
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing " + "ServletWebServerFactory bean.");
}
// 如果是 > 1 个,抛出 ApplicationContextException 异常,因为不知道初始化哪个
if (beanNames.length > 1) {
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple " + "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
}
// 获得 ServletWebServerFactory 类型对应的 Bean 对象
return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
}
```
- 默认情况下,此处返回的会是 `org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory` 对象。
- 在我们引入 `spring-boot-starter-web` 依赖时,默认会引入 `spring-boot-starter-tomcat` 依赖。此时,`org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration` 在自动配置时,会配置出 TomcatServletWebServerFactory Bean 对象。因此,此时会获得 TomcatServletWebServerFactory 对象。
- `<1.2>` 处,调用 `#getSelfInitializer()` 方法,获得 ServletContextInitializer 对象。代码如下:
```
// ServletWebServerApplicationContext.java
private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
return this::selfInitialize; // 和下面等价
// return new ServletContextInitializer() {
//
// @Override
// public void onStartup(ServletContext servletContext) throws ServletException {
// selfInitialize(servletContext);
// }
//
// };
}
```
- 嘻嘻,返回的是 ServletContextInitializer 匿名对象,内部会调用 `#selfInitialize(servletContext)` 方法。该方法会在 WebServer 创建后,进行初始化。详细解析,见 [「2.4.2 finishRefresh」](https://svip.iocoder.cn/Spring-Boot/ServletWebServerApplicationContext/#) 小节。
- `<1.3>` 处,调用 `ServletWebServerFactory#getWebServer(ServletContextInitializer)` 方法,创建(获得) WebServer 对象。在这个过程中,会调用 [「2.4.2 selfInitialize」](https://svip.iocoder.cn/Spring-Boot/ServletWebServerApplicationContext/#) 方法。
- 至此,和 [《精尽 Spring MVC 源码分析 —— 容器的初始化(四)之 Spring Boot 集成》](http://svip.iocoder.cn/Spring-MVC/context-init-integration-with-SpringBoot) 文章,基本是能穿起来了。
- `<2>` 处TODO 1002 不知道原因。有知道的胖友,星球里告知下哟。
- `<3>` 处,调用父 `#initPropertySources()` 方法,初始化 PropertySource 。
### 2.4.2 selfInitialize
`#selfInitialize()` 方法,初始化 WebServer 。代码如下:
```
// ServletWebServerApplicationContext.java
private void selfInitialize(ServletContext servletContext) throws ServletException {
// <1> 添加 Spring 容器到 servletContext 属性中。
prepareWebApplicationContext(servletContext);
// <2> 注册 ServletContextScope
registerApplicationScope(servletContext);
// <3> 注册 web-specific environment beans ("contextParameters", "contextAttributes")
WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
// <4> 获得所有 ServletContextInitializer ,并逐个进行启动
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}
}
```
- `<1>` 处,调用 `#prepareWebApplicationContext(ServletContext servletContext)` 方法,添加 Spring 容器到 servletContext 属性中。代码如下:
```
// ServletWebServerApplicationContext.java
protected void prepareWebApplicationContext(ServletContext servletContext) {
// 如果已经在 ServletContext 中,则根据情况进行判断。
Object rootContext = servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
if (rootContext != null) {
// 如果是相同容器,抛出 IllegalStateException 异常。说明可能有重复的 ServletContextInitializers 。
if (rootContext == this) {
throw new IllegalStateException("Cannot initialize context because there is already a root application context present - " + "check whether you have multiple ServletContextInitializers!");
}
// 如果不同容器,则直接返回。
return;
}
Log logger = LogFactory.getLog(ContextLoader.class);
servletContext.log("Initializing Spring embedded WebApplicationContext");
try {
// <X> 设置当前 Spring 容器到 ServletContext 中
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this);
// 打印日志
if (logger.isDebugEnabled()) {
logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
}
// <Y> 设置到 `servletContext` 属性中。
setServletContext(servletContext);
// 打印日志
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - getStartupDate();
logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
}
} catch (RuntimeException | Error ex) {
logger.error("Context initialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
throw ex;
}
}
```
- 虽然代码非常长,但是核心在 `<X>` 和 `<Y>` 处。
- 通过 `<X>` 处,从 `servletContext` 的属性种,可以拿到其拥有的 Spring 容器。
- 通过 `<Y>` 处Spring 容器的 `servletContext` 属性,可以拿到 ServletContext 对象。
- `<2>` 处,调用 `#registerApplicationScope(ServletContext servletContext)` 方法,注册 ServletContextScope 。代码如下:
```
// ServletWebServerApplicationContext.java
private void registerApplicationScope(ServletContext servletContext) {
ServletContextScope appScope = new ServletContextScope(servletContext);
getBeanFactory().registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
// Register as ServletContext attribute, for ContextCleanupListener to detect it.
servletContext.setAttribute(ServletContextScope.class.getName(), appScope);
}
```
- 不用细了解。
- `<3>` 处,调用 `WebApplicationContextUtils#registerEnvironmentBeans(ConfigurableListableBeanFactory bf, ServletContext sc)` 方法,注册 web-specific environment beans `("contextParameters", "contextAttributes")` 。这样,从 BeanFactory 中,也可以获得到 `servletContext` 。当然,也可以暂时不用细了解。
- `<4>` 处,获得所有 ServletContextInitializer ,并逐个进行启动。关于这块的解析,我们在 [《精尽 Spring MVC 源码分析 —— 容器的初始化(四)之 Spring Boot 集成》](http://svip.iocoder.cn/Spring-MVC/context-init-integration-with-SpringBoot) 中,已经详细写到。😈
- 至此,内嵌的 Servlet Web 服务器,已经能够被请求了。
## 2.5 finishRefresh
覆写 `#finishRefresh()` 方法,在容器初始化完成时,启动 WebServer 。代码如下:
```
// ServletWebServerApplicationContext.java
@Override
protected void finishRefresh() {
// <1> 调用父方法
super.finishRefresh();
// <2> 启动 WebServer
WebServer webServer = startWebServer();
// <3> 如果创建 WebServer 成功,发布 ServletWebServerInitializedEvent 事件
if (webServer != null) {
publishEvent(new ServletWebServerInitializedEvent(webServer, this));
}
}
```
- `<1>` 处,调用 `#finishRefresh()` 方法,执行父逻辑。这块,暂时不用了解。
- `<2>` 处,调用 `#startWebServer()` 方法,启动 WebServer 。详细解析,见 [「2.5.1 startWebServer」](https://svip.iocoder.cn/Spring-Boot/ServletWebServerApplicationContext/#) 。
- `<3>` 处,如果创建 WebServer 成功,发布 ServletWebServerInitializedEvent 事件。
### 2.5.1 startWebServer
`#startWebServer()` 方法,启动 WebServer 。代码如下:
```
// ServletWebServerApplicationContext.java
private WebServer startWebServer() {
WebServer webServer = this.webServer;
if (webServer != null) {
webServer.start();
}
return webServer;
}
```
## 2.6 onClose
覆写 `#onClose()` 方法,在 Spring 容器被关闭时,关闭 WebServer 。代码如下:
```
// ServletWebServerApplicationContext.java
@Override
protected void onClose() {
// 调用父方法
super.onClose();
// 停止 WebServer
stopAndReleaseWebServer();
}
```
# 3. AnnotationConfigServletWebServerApplicationContext
`org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext` ,继承 ServletWebServerApplicationContext 类,实现 AnnotationConfigRegistry 接口,进一步提供了两个功能:
> 艿艿:不过一般情况下,我们用不到这两个功能。简单看了下,更多的是单元测试,需要使用到这两个功能。
- 从指定的 `basePackages` 包中,扫描 BeanDefinition 们。
- 从指定的 `annotatedClasses` 注解的配置类Configuration读取 BeanDefinition 们。
> 所以啊,这类,简单看看就成啦。
## 3.1 构造方法
```
// AnnotationConfigServletWebServerApplicationContext.java
private final AnnotatedBeanDefinitionReader reader;
private final ClassPathBeanDefinitionScanner scanner;
/**
* 需要被 {@link #reader} 读取的注册类们
*/
private final Set<Class<?>> annotatedClasses = new LinkedHashSet<>();
/**
* 需要被 {@link #scanner} 扫描的包
*/
private String[] basePackages;
public AnnotationConfigServletWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
public AnnotationConfigServletWebServerApplicationContext(DefaultListableBeanFactory beanFactory) {
super(beanFactory);
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
public AnnotationConfigServletWebServerApplicationContext(Class<?>... annotatedClasses) {
this();
// <1> 注册指定的注解的类们
register(annotatedClasses);
// 初始化 Spring 容器
refresh();
}
public AnnotationConfigServletWebServerApplicationContext(String... basePackages) {
this();
// <2> 扫描指定包
scan(basePackages);
// 初始化 Spring 容器
refresh();
}
```
- ```
<1>
```
处,如果已经传入
```
annotatedClasses
```
参数,则调用
```
#register(Class<?>... annotatedClasses)
```
方法,设置到
```
annotatedClasses
```
中。然后,调用
```
#refresh()
```
方法,初始化 Spring 容器。代码如下:
```
// AnnotationConfigServletWebServerApplicationContext.java
@Override // 实现自 AnnotationConfigRegistry 接口
public final void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
this.annotatedClasses.addAll(Arrays.asList(annotatedClasses));
}
```
- ```
<2>
```
处,如果已经传入
```
basePackages
```
参数,则调用
```
#scan(String... basePackages)
```
方法,设置到
```
annotatedClasses
```
中。然后,调用
```
#refresh()
```
方法,初始化 Spring 容器。代码如下:
```
// AnnotationConfigServletWebServerApplicationContext.java
@Override
public final void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
this.basePackages = basePackages;
}
```
## 3.2 prepareRefresh
覆写 `#prepareRefresh()` 方法,代码如下:
```
// AnnotationConfigServletWebServerApplicationContext.java
@Override // 实现自 AbstractApplicationContext 抽象类
protected void prepareRefresh() {
// 清空 scanner 的缓存
this.scanner.clearCache();
// 调用父类
super.prepareRefresh();
}
```
- 在 Spring 容器初始化前,需要清空 `scanner` 的缓存。
## 3.3 postProcessBeanFactory
覆写 `#postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)` 方法,执行 BeanDefinition 的读取。代码如下:
```
// AnnotationConfigServletWebServerApplicationContext.java
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 调用父类
super.postProcessBeanFactory(beanFactory);
// 扫描指定的包
if (this.basePackages != null && this.basePackages.length > 0) {
this.scanner.scan(this.basePackages);
}
// 注册指定的注解的类们定的
if (!this.annotatedClasses.isEmpty()) {
this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
}
}
```
- 实际场景下,`this.basePackages` 和 `annotatedClasses` 都是空的。所以呢哈哈哈哈AnnotationConfigServletWebServerApplicationContext 基本没啥子用~
# 666. 彩蛋
简单小文一篇~很妥~
参考和推荐如下文章:
- oldflame-Jm
- [《Spring boot 源码分析-AnnotationConfigApplicationContext 非 web 环境下的启动容器2](https://blog.csdn.net/jamet/article/details/77417997)
- [《Spring boot 源码分析-AnnotationConfigEmbeddedWebApplicationContext 默认 web 环境下的启动容器3](https://blog.csdn.net/jamet/article/details/77428946)