【三】Spring 源码分析之启动主流程---SpringApplication的prepareContext方法
该方法主要是为刷新spring容器做准备
入口在SpringApplication类的run方法调用prepareContext方法,
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
源码
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// 设置Spring容器的环境信息
context.setEnvironment(environment);
// 回调方法,Spring容器创建之后做一些额外的事
postProcessApplicationContext(context);
// SpringApplication的的初始化器开始工作
applyInitializers(context);
// 遍历调用SpringApplicationRunListener的contextPrepared方法。目前只是将这个事件广播器注册到Spring容器中
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 把应用程序参数持有类注册到Spring容器中,并且是一个单例
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
// 广播出ApplicationPreparedEvent事件给相应的监听器执行
listeners.contextLoaded(context);
}
做了这8件事
1.context.setEnvironment(environment)
设置ApplicationContext容器的环境Environment信息。
public void setEnvironment(ConfigurableEnvironment environment) {
super.setEnvironment(environment);
this.reader.setEnvironment(environment);
this.scanner.setEnvironment(environment);
}
2.postProcessApplicationContext方法。
由于beanNameGenerator和resourceLoader此时为空,所以什么都没做。
源码:
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
if (this.beanNameGenerator != null) {
context.getBeanFactory().registerSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
}
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
((GenericApplicationContext) context)
.setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader) context)
.setClassLoader(this.resourceLoader.getClassLoader());
}
}
}
3.applyInitializers方法
SpringApplication实例化的时候创建的那6个初始化器Initializer开始工作,调用他们每个初始化器的initialize方法。
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
详细介绍每个初始化器中了什么
3.1 DelegatingApplicationContextInitializer
源码
public void initialize(ConfigurableApplicationContext context) {
ConfigurableEnvironment environment = context.getEnvironment();
List<Class<?>> initializerClasses = getInitializerClasses(environment);
// 这里由于initializerClasses是空的,所以并没有执行后面的逻辑。
if (!initializerClasses.isEmpty()) {
applyInitializerClasses(context, initializerClasses);
}
}
这里由于initializerClasses是空的,所以并没有执行后面的逻辑。
3.2 ContextIdApplicationContextInitializer
源码
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.setId(getApplicationId(applicationContext.getEnvironment()));
}
这里是给ApplicationContext设置ID,我debug到这里,设置的id为application
3.3 ConfigurationWarningsApplicationContextInitializer
源码:
public void initialize(ConfigurableApplicationContext context) {
context.addBeanFactoryPostProcessor(
new ConfigurationWarningsPostProcessor(getChecks()));
}
往ApplicationContext容器中注册了beanFactoryPostProcessors后置处理器ConfigurationWarningsPostProcessor
3.4 ServerPortInfoApplicationContextInitializer
源码:
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addApplicationListener(
new ApplicationListener<EmbeddedServletContainerInitializedEvent>() {
@Override
public void onApplicationEvent(
EmbeddedServletContainerInitializedEvent event) {
ServerPortInfoApplicationContextInitializer.this
.onApplicationEvent(event);
}
});
}
往ApplicationContext容器中注册了事件监听器(我们暂时就叫它ServerPortInfoApplicationContextInitializer$listener),监听EmbeddedServletContainerInitializedEvent事件。
3.5 SharedMetadataReaderFactoryContextInitializer
源码
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addBeanFactoryPostProcessor(
new CachingMetadataReaderFactoryPostProcessor());
}
往ApplicationContext容器中注册了beanFactoryPostProcessors后置处理器CachingMetadataReaderFactoryPostProcessor
3.6 AutoConfigurationReportLoggingInitializer
源码
public void initialize(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
applicationContext.addApplicationListener(new AutoConfigurationReportListener());
if (applicationContext instanceof GenericApplicationContext) {
// Get the report early in case the context fails to load
this.report = ConditionEvaluationReport
.get(this.applicationContext.getBeanFactory());
}
}
往ApplicationContext容器中注册了事件监听器AutoConfigurationReportListener
4.listeners.contextPrepared(context)方法
源码:
调用SpringApplicationRunListeners类的contextPrepared方法
public void contextPrepared(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.contextPrepared(context);
}
}
这里的this.listeners只有一个,是EventPublishingRunListener类。
实际上调用了EventPublishingRunListener类的contextPrepared方法,而这个方法里面还是空的,等于什么都没做。
5.打印日志
源码
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
springboot启动时控制台的这两句日志就是这里打印的。
2019-02-21 11:07:54.421 INFO 60456 --- [ main] com.sid.App : Starting App on SKY-20180917SEE with PID 60456 (D:\gitrep\test-aop\target\classes started by Administrator in D:\gitrep\test-aop)
2019-02-21 11:07:57.419 INFO 60456 --- [ main] com.sid.App : No active profile set, falling back to default profiles: default
6.把SpringApplicationArguments、SpringBootBanner以单例形式注册到BeanFactory中
源码
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
7.load(context, sources.toArray(new Object[sources.size()]))方法
源码
// Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
这里的sources就是我们编写的带@SpringBootApplication注解的启动类
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
load方法源码
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();
}
做了2件事:
7.1 createBeanDefinitionLoader方法
创建BeanDefinitionLoader
7.2 loader.load方法
此时只是把资源类(这里只有@SpringBootApplication注解修饰的启动类)注册到BeanFactory中。
流程图:
做了4件事:
1.BeanDefinitionLoader把资源加载进来
2.由BeanDefinitionLoader内部的AnnotatedBeanDefinitionReader解析资源
3.AnnotatedBeanDefinitionReader生成beanDefinition
4.AnnotatedBeanDefinitionReader将BeanDefinition注册到BeanFactory的注册表中。注册表是Map类型,key是beanName,value是BeanDefinition
8.listeners.contextLoaded(context)方法
调用SpringApplicationRunListeners类的contextLoaded方法
public void contextLoaded(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.contextLoaded(context);
}
}
该方法中的this.listeners其实只有一个 EventPublishingRunListener类
实际上是调用的EventPublishingRunListener类的contextLoaded方法
源码:
public void contextLoaded(ConfigurableApplicationContext context) {
// 获取SpringApplication实例化的时候创建的10个监听器
for (ApplicationListener<?> listener : this.application.getListeners()) {
// 如果该监听器是ApplicationContextAware的实例,则把ApplicationContext设置到监听器中
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
// 把SpringApplication实例化的时候创建的10个监听器Listener注册到ApplicationContext容器中。
context.addApplicationListener(listener);
}
// 广播出ApplicationPreparedEvent事件给相应的监听器执行
this.initialMulticaster.multicastEvent(
new ApplicationPreparedEvent(this.application, this.args, context));
}
该方法做了4件事
8.1 获取SpringApplication实例化的时候创建的10个监听器。
org.springframework.boot.ClearCachesApplicationListener
org.springframework.boot.builder.ParentContextCloserApplicationListener
org.springframework.boot.context.FileEncodingApplicationListener
org.springframework.boot.context.config.AnsiOutputApplicationListener
org.springframework.boot.context.config.ConfigFileApplicationListener
org.springframework.boot.context.config.DelegatingApplicationListener
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
org.springframework.boot.logging.ClasspathLoggingApplicationListener
org.springframework.boot.logging.LoggingApplicationListener
org.springframework.boot.autoconfigure.BackgroundPreinitializer
8.2 如果该监听器是ApplicationContextAware的实例,则把ApplicationContext设置到监听器中。
8.3 把SpringApplication实例化的时候创建的10个监听器Listener注册到ApplicationContext容器中。
8.4 广播出ApplicationPreparedEvent事件给相应的监听器。
这里有如下几个监听器,接受到了该事件,并且做出相应的逻辑
8.4.1 ConfigFileApplicationListener
接收到该事件做的逻辑源码
private void onApplicationPreparedEvent(ApplicationEvent event) {
this.logger.replayTo(ConfigFileApplicationListener.class);
addPostProcessors(((ApplicationPreparedEvent) event).getApplicationContext());
}
给ApplicationContext添加BeanFactoryPostProcessor后置处理器PropertySourceOrderingPostProcessor
8.4.2 LoggingApplicationListener
接收到该事件做的逻辑源码
private void onApplicationPreparedEvent(ApplicationPreparedEvent event) {
ConfigurableListableBeanFactory beanFactory = event.getApplicationContext()
.getBeanFactory();
if (!beanFactory.containsBean(LOGGING_SYSTEM_BEAN_NAME)) {
beanFactory.registerSingleton(LOGGING_SYSTEM_BEAN_NAME, this.loggingSystem);
}
}
给beanFactory注册了单例 springBootLoggingSystem
8.4.3 BackgroundPreinitializer
接收到该事件做的逻辑源码
由于这个监听器没有监听ApplicationPreparedEvent事件,所以什么逻辑都没做
public void onApplicationEvent(SpringApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
if (preinitializationStarted.compareAndSet(false, true)) {
performPreinitialization();
}
}
if ((event instanceof ApplicationReadyEvent
|| event instanceof ApplicationFailedEvent)
&& preinitializationStarted.get()) {
try {
preinitializationComplete.await();
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
8.4.4 DelegatingApplicationListener
接收到该事件做的逻辑源码
由于这个监听器没有监听ApplicationPreparedEvent事件,所以什么逻辑都没做
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
List<ApplicationListener<ApplicationEvent>> delegates = getListeners(
((ApplicationEnvironmentPreparedEvent) event).getEnvironment());
if (delegates.isEmpty()) {
return;
}
this.multicaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<ApplicationEvent> listener : delegates) {
this.multicaster.addApplicationListener(listener);
}
}
if (this.multicaster != null) {
this.multicaster.multicastEvent(event);
}
}
下一篇: 高效使用Github寻找开源项目