关联博文:
SpringBoot启动时都做了哪些事(一)?
SpringBoot启动时都做了哪些事(二)?
SpringBoot启动时都做了哪些事(三)?
SpringBoot启动时都做了哪些事(四)?
接上一篇SpringBoot启动时都做了哪些事(二)?后,我们继续分析SpringBoot启动过程流程。
本文我们开始分析应用上下文的创建和配置。核心流程梳理如下:
- 创建应用上下文实例
AnnotationConfigServletWebServerApplicationContext
,这里会同步创建AnnotatedBeanDefinitionReader
和ClassPathBeanDefinitionScanner
并注册一系列"AnnotationConfigProcessor"
。其父类GenericApplicationContext
的构造方法中会触发DefaultListableBeanFactory
的实例化流程。 - 准备应用上下文
- 为应用上下文绑定环境实例
- 尝试为context设置ResourceLoader和ClassLoader,并为BeanFactory进行设置ConversionService
- 触发每一个ApplicationContextInitializer的initialize方法
- listeners.contextPrepared(context);广播ApplicationContextInitializedEvent事件
- 注册单例springApplicationArguments—DefaultApplicationArguments
- 注册单例springBootBanner
- 设置是否允许BeanDefinition覆盖,默认是false
- 加载主启动应用类,注册启动类的BeanDefinition到容器DefaultListableBeanFactory
- listeners.contextLoaded(context);触发EventPublishingRunListener的contextLoaded方法,广播ApplicationPreparedEvent事件
【1】创建应用上下文
如下所示如果contextClass 为null,那么根据webApplicationType
来获取上下文class类型,然后使用BeanUtils实例化得到ConfigurableApplicationContext
。本文这里是AnnotationConfigServletWebServerApplicationContext
。
//SpringApplication的createApplicationContext方法
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);
}
如下是三个应用上下文类型,分别针对不同的环境。
public static final String DEFAULT_CONTEXT_CLASS =
"org.springframework.context.annotation.AnnotationConfigApplicationContext";
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS =
"org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS =
"org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
在AnnotationConfigServletWebServerApplicationContext
的构造方法中,初始化了reader和scanner。
public AnnotationConfigServletWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
AnnotatedBeanDefinitionReader
是ClassPathBeanDefinitionScanner
的替代方案,用来显示注册bean。ClassPathBeanDefinitionScanner
则是我们常见的bean扫描器,用来扫描classpath下的组件(@Component/@Repository/@Service/@Controller)并注册bean定义到容器中。
这里我们要特别注意这个AnnotatedBeanDefinitionReader,如下所示其构造函数中触发了一些注解后置处理器。
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
// 这句话很重要
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
registerAnnotationConfigProcessors这个方法做了什么呢?我们这里先简单总结一下:
- 对 beanFactory 添加依赖比较器
AnnotationAwareOrderComparator
和 自动装配解析器ContextAnnotationAutowireCandidateResolver
- 注册
ConfigurationClassPostProcessor
用于对 @Configuration 类进行引导处理 - 注册
AutowiredAnnotationBeanPostProcessor
处理 @Autowired @Value 和 JSR-330的@Inject 还有 @Lookup 注解 - 注册
CommonAnnotationBeanPostProcessor
用来处理 @PostConstruct @PreDestroy @Resource PersistenceAnnotationBeanPostProcessor
用于 JPA场景DefaultEventListenerFactory
、EventListenerMethodProcessor
支持 @EventListener用于将注解方法注册为单独的ApplicationListener实例
本文这里只注册了如下五个:
// ConfigurationClassPostProcessor
0 = "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"
// AutowiredAnnotationBeanPostProcessor
1 = "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"
// CommonAnnotationBeanPostProcessor
2 = "org.springframework.context.annotation.internalCommonAnnotationProcessor"
//EventListenerMethodProcessor
3 = "org.springframework.context.event.internalEventListenerProcessor"
// DefaultEventListenerFactory
4 = "org.springframework.context.event.internalEventListenerFactory"
创建完上下文后就该获取异常报告器SpringBootExceptionReporter,这里getSpringFactoriesInstances我们再第一篇文章中讲过这里不再赘述。
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
【2】准备上下文
也就是prepareContext方法。这里会为context和BeanFactory做一些配置,触发每个ApplicationContextInitializer
的initialize方法并广播ApplicationContextInitializedEvent
、ApplicationPreparedEvent
事件。
// SpringApplication
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
// 为应用上下文绑定环境实例
context.setEnvironment(environment);
//尝试为context设置ResourceLoader和ClassLoader,并为BeanFactory进行设置ConversionService
postProcessApplicationContext(context);
// 触发每一个ApplicationContextInitializer的initialize方法
applyInitializers(context);
//广播ApplicationContextInitializedEvent事件
listeners.contextPrepared(context);
//打印启动信息
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 注册单例springApplicationArguments---DefaultApplicationArguments
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
// 注册单例springBootBanner
//org.springframework.boot.SpringApplicationBannerPrinter.PrintedBanner
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
// 设置是否允许BeanDefinition覆盖,默认是false
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 懒加载配置--本文这里是false
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources 获取的类信息,本文这里只有主启动类
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//加载bean到应用上下文
load(context, sources.toArray(new Object[0]));
//发布并广播ApplicationPreparedEvent事件
listeners.contextLoaded(context);
}
① postProcessApplicationContext
ApplicationContext的后置处理,主要尝试为其设置resourceLoader 、ClassLoader,并尝试为BeanFactory注册单例bean–internalConfigurationBeanNameGenerator
及设置ConversionService。
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
// 尝试注册单例internalConfigurationBeanNameGenerator,本文这里为null
if (this.beanNameGenerator != null) {
//注册单例,其实就是放入一级缓存和Set<String> registeredSingletons中
context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
}
// 本文这里为null 不进入方法
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
// 设置资源加载器
((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
// 设置类加载器
((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
}
}
// 本文这里默认为true,为BeanFactory设置ConversionService
if (this.addConversionService) {
// 为BeanFactory设置转换服务
context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
}
}
② applyInitializers
本质是获取容器里面的所有ApplicationContextInitializer ,触发每一个的initialize方法。
protected void applyInitializers(ConfigurableApplicationContext context) {
// 这里得到是一个asUnmodifiableOrderedSet(this.initializers);,也就是只读的
for (ApplicationContextInitializer initializer : getInitializers()) {
// 这里获取的是接口泛型的类型,比如ConfigurableApplicationContext
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
//触发每个初始化器的初始化方法
initializer.initialize(context);
}
}
我们在SpringBoot启动时都做了哪些事(一)?一文中分析SpringApplication实例过程中提到过ApplicationContextInitializer 的获取。
本文这里获取的有8个,对其进行遍历校验类型然后触发每个initializer 的方法initialize
0 = {SharedMetadataReaderFactoryContextInitializer@3564}
1 = {DelegatingApplicationContextInitializer@3565}
2 = {ContextIdApplicationContextInitializer@3566}
3 = {ConditionEvaluationReportLoggingListener@3567}
4 = {RestartScopeInitializer@3568}
5 = {ConfigurationWarningsApplicationContextInitializer@3569}
6 = {RSocketPortInfoApplicationContextInitializer@3570}
7 = {ServerPortInfoApplicationContextInitializer@3571}
SharedMetadataReaderFactoryContextInitializer
向应用上下文的List<BeanFactoryPostProcessor> beanFactoryPostProcessors
添加了CachingMetadataReaderFactoryPostProcessor
。
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addBeanFactoryPostProcessor(new CachingMetadataReaderFactoryPostProcessor());
}
ConfigurationWarningsApplicationContextInitializer
向应用上下文的List<BeanFactoryPostProcessor> beanFactoryPostProcessors
添加了ConfigurationWarningsPostProcessor
。
@Override
public void initialize(ConfigurableApplicationContext context) {
context.addBeanFactoryPostProcessor(new ConfigurationWarningsPostProcessor(getChecks()));
}
protected Check[] getChecks() {
return new Check[] { new ComponentScanPackageCheck() };
}
也就是说上面两个ApplicationContextInitializer增加了两个BeanFactoryPostProcessor。
ConditionEvaluationReportLoggingListener
其主要向AbstractApplicationContext
的成员Set<ApplicationListener<?>> applicationListeners
添加了ConditionEvaluationReportListener
。
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
// 添加监听
applicationContext.addApplicationListener(new ConditionEvaluationReportListener());
if (applicationContext instanceof GenericApplicationContext) {
// Get the report early in case the context fails to load
// 得到(实例化)ConditionEvaluationReport并为其设置parent
this.report = ConditionEvaluationReport.get(this.applicationContext.getBeanFactory());
}
}
RSocketPortInfoApplicationContextInitializer
其主要向AbstractApplicationContext
的成员Set<ApplicationListener<?>> applicationListeners
添加了RSocketPortInfoApplicationContextInitializer.Listener
。
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addApplicationListener(new Listener(applicationContext));
}
ServerPortInfoApplicationContextInitializer
其主要向AbstractApplicationContext
的成员Set<ApplicationListener<?>> applicationListeners
添加了ServerPortInfoApplicationContextInitializer
。
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addApplicationListener(this);
}
上面三个ApplicationContextInitializer注册了三个ApplicationListener到应用上下文中。
DelegatingApplicationContextInitializer
尝试从环境配置信息获取context.initializer.classes
对应的值,实例化那些bean并触发每个的initialize方法。本文这里没有任何动作。
@Override
public void initialize(ConfigurableApplicationContext context) {
ConfigurableEnvironment environment = context.getEnvironment();
// 从environment获取context.initializer.classes配置的信息
// 本文这里为空,不触发任何动作
List<Class<?>> initializerClasses = getInitializerClasses(environment);
if (!initializerClasses.isEmpty()) {
applyInitializerClasses(context, initializerClasses);
}
}
ContextIdApplicationContextInitializer
获取应用上下文ID对象contextId ,为applicationContext设置ID并注册单例bean到BeanFactory中。
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ContextId contextId = getContextId(applicationContext);
applicationContext.setId(contextId.getId());
applicationContext.getBeanFactory().registerSingleton(ContextId.class.getName(), contextId);
}
RestartScopeInitializer
注册restart scope到BeanFactory的Map<String, Scope> scopes
中。
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.getBeanFactory().registerScope("restart", new RestartScope());
}
③ listeners.contextPrepared(context)
本文this指的是SpringApplicationRunListeners
,这里只有一个EventPublishingRunListener
,将会广播ApplicationContextInitializedEvent
事件。
void contextPrepared(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.contextPrepared(context);
}
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
this.initialMulticaster
.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}
有如下三个监听器对ApplicationContextInitializedEvent事件感兴趣。
0 = {RestartApplicationListener@3945}
1 = {BackgroundPreinitializer@3946}
2 = {DelegatingApplicationListener@3947}
logStartupInfo(context.getParent() == null);
打印启动信息:
logStartupProfileInfo(context);
打印信息:
④ load
这里将会加载主启动应用类,注册启动类的BeanDefinition到容器DefaultListableBeanFactory中。
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}
创建BeanDefinitionLoader
,这里registry是AnnotationConfigServletWebServerApplicationContext
实例。
protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {
return new BeanDefinitionLoader(registry, sources);
}
BeanDefinitionLoader构造器如下其配置了annotatedReader 、xmlReader以及scanner 。这三个在整个应用中是非常重要的基础设置,其完成了bean的扫描与beandefinition的注册。
BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
Assert.notNull(registry, "Registry must not be null");
Assert.notEmpty(sources, "Sources must not be empty");
this.sources = sources;
this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
this.xmlReader = new XmlBeanDefinitionReader(registry);
if (isGroovyPresent()) {
this.groovyReader = new GroovyBeanDefinitionReader(registry);
}
this.scanner = new ClassPathBeanDefinitionScanner(registry);
this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}
这里最终会如下所示,调用AnnotatedBeanDefinitionReader
注册应用主类,也就是注册BeanDefinition
到beanDefinitionMap
中并记录beanName
到beanDefinitionNames
中。
⑤ listeners.contextLoaded
如下所示,这里实际上会触发EventPublishingRunListener
的contextLoaded
方法。
void contextLoaded(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.contextLoaded(context);
}
}
this.application
指的是SpringApplication
实例。这个方法会将SpringApplication
中的ApplicationListener
添加到ConfigurableApplicationContext
的applicationListeners
中。如果applicationEventMulticaster
不为null,也会同时放到applicationEventMulticaster的成员defaultRetriever.applicationListeners
中。
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
// 将监听添加到应用上下文中
for (ApplicationListener<?> listener : this.application.getListeners()) {
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
context.addApplicationListener(listener);
}
// 广播ApplicationPreparedEvent事件
this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
接下来会广播ApplicationPreparedEvent
事件,有如下七个监听器对该事件感兴趣。
0 = {RestartApplicationListener@4405}
1 = {CloudFoundryVcapEnvironmentPostProcessor@4406}
2 = {ConfigFileApplicationListener@4407}
3 = {LoggingApplicationListener@4409}
4 = {BackgroundPreinitializer@4410}
5 = {DelegatingApplicationListener@4412}
6 = {DevToolsLogFactory$Listener@4414}
到此,我们广播了ApplicationStartingEvent
、ApplicationEnvironmentPreparedEvent
、ApplicationContextInitializedEvent
以及ApplicationPreparedEvent
事件。