前言
上下文Context可以说spring boot中最重要的一个概念,不仅包含了tomcat和spring mvc的启动和管理,还对spring mvc原有模式中的bean注册进行了大幅简化,理解Spring boot的Context可以说是理解spring boot的基础。
原理分析(六)介绍了spring boot启动的主流程,run方法中最主要的部分即上下文的准备。
public ConfigurableApplicationContext run(String... args) {
......
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
......
return context;
}
上文代码中包括context的创建、准备、刷新和刷新后处理。刷新后处理的方法afterRefresh是模板方法,供子类继承填充代码逻辑。
上下文创建
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);
}
上下文创建createApplicationContext还是会依据SERVLET、REACTIVE和NONE类型来创建相应的上下文。类型解释再引用一下原理分析(六)的内容。
SERVLET、REACTIVE和NONE。我们讲spring mvc是Servlet容器,所以服务即SERVLET WEB类型。REACTIVE也是一种WEB服务的类型,代表着非阻塞响应式编程,正是spirng mvc不擅长的事,具体可以参考spring-webflux。NONE类型说这个服务不是WEB类型,是其他服务类型。
Servlet服务对应的环境上下文是AnnotationConfigServletWebServerApplicationContext类,Reactive服务对应的环境上下文是AnnotationConfigReactiveWebServerApplicationContext类,而默认的上下文AnnotationConfigApplicationContext类。
上下文Context的定义
根据ApplicationContext接口定义可以发现上下文的本质其实是一个“杂货铺”,继承的父类显示了上下文中包含的内容。
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
@Nullable
String getId();
String getApplicationName();
String getDisplayName();
long getStartupDate();
@Nullable
ApplicationContext getParent();
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
- 继承的父类接口EnvironmentCapable赋予了上下文获取应用程序的运行环境配置的能力。环境配置包括profile和properties配置,properties配置不仅包括项目内的properties文件,还有JVM system properties、操作系统环境变量等。
- ListableBeanFactory和HierarchicalBeanFactory赋予了上下文获取bean、注册bean的能力。
- MessageSource主要是国际化配置,比如语言等
- ApplicationEventPublisher提供了上下文发送上下文状态改变事件的能力。这部分内容在原理分析(七)中有比较详细的介绍。
- ResourcePatternResolver继承了ResourceLoader,是用来做资源的格式解析,比如各种配置文件等等。
这里需要注意的是,ApplicationContext接口中定义的都是getter类型的接口方法,没有setter类型的接口方法。这是因为不是所有上下文对象都提供修改内容的接口方法,只有ConfigurableApplicationContext接口的实现类提供了setter方法,可以修改上下文中的配置。这样做是为了防止上下文内容被随意变更。
上下文Context的实现
![spring boot原理分析(八):上下文Context即世界1-AnnotationConfigServletWebServerApplicationContext.png](https://i-blog.csdnimg.cn/blog_migrate/972665d2a61175a9b06a674af0a4358f.png)
在ApplicationContext的更上层是基础层的接口,上面已经介绍了,这些接口打包构成了上下文的“杂货铺”。ApplicationContext下层是其不同类型的子接口或者子类,主要是根据功能或者应用对象对上下文进行了分类。
WebApplicationContext接口添加了ServletContext getServletContext()方法。ServletContext的相关内容在spring mvc的原理(七)中,ServletConfig能够获取ServletContext的配置,其实代表就是spring mvc的应用本身。
WebServerApplicationContext的接口里增加了WebServer getWebServer()的方法,这里具体代表的就是tomcat服务器本身。
ConfigurableApplicationContext上面已经介绍过,是一个功能性的子接口,为ApplicationContext提供了setter的方法,所有有继承改接口的子类都拥有修改配置的能力。
所以这样就很容易判断ConfigurableWebApplicationContext和ConfigurableWebServerApplicationContext具有的能力,实际上是功能分类和应用对象分类的一个拼合。
接下来比较重要的是GenericApplicationContext,这个子类的特别之处在于继承了bean定义的注册BeanDefinitionRegistry。BeanDefinitionRegistry在原理分析(三)有过介绍,是用来用来注册bean的。GenericApplicationContext的使用方法的官方解释是,先使用BeanDefinitionRegistry注册一系列的bean,然后调用 AbstractApplicationContext.refresh()初始化这些bean。与普通ApplicationContext的实现类不同的是,GenericApplicationContext不会每次refresh创建一个新的BeanFactory实例,而是在构造时就会获取并持有一个BeanFactory实例,AbstractApplicationContext.refresh()可能只会被调用一次。
使用以上子类或者子接口的功能进行拼合,就得出了GenericWebApplicationContext和ServletWebServerApplicationContext这两个类。
最后对于AnnotationConfigServletWebServerApplicationContext,除了上述所有子接口和子类的功能之外,还实现了AnnotationConfigRegistry接口。AnnotationConfigRegistry这个接口主要是负责bean注解的注册和扫描工作,比如@Configuration注解。
附
本文主要介绍了Spring boot的ApplicationContext的定义实现和创建,后续会对上下文的准备和刷新进行介绍。