springboot(2.4.1)源代码分析四prepareContext上下文准备
上一篇讲了springboot的配置环境准备,接下来就是应用上下文的初始化、准备以及加载,下面还是从run方法看起。
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);//打印banner
context = createApplicationContext(); //创建上下文
context.setApplicationStartup(this.applicationStartup);//设置启动步骤,程序可以自己记录一些启动数据
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);//准备上下文
refreshContext(context);
afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
listeners.started(context, timeTakenToStartup);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
2.4.0过后的初始化上下文可能稍有不同,之前是通过class探测出当前是属于那种类型的应用,然后创建对应的上下文,现在通过META-INF/spring.factories配置的org.springframework.boot.ApplicationContextFactory来引入上下文工厂类,目前默认的就2个org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext.Factory与org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext.Factory,分别对应响应式web与常规的servlet应用,每个工厂类自己去判断是否创建对应的上下文,如reactive上下文工厂:
public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
return (webApplicationType != WebApplicationType.REACTIVE) ? null
: new AnnotationConfigReactiveWebServerApplicationContext();
}
准备上下文中最核心的方法
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment); //设置运行环境
postProcessApplicationContext(context); //设置BEAN_NAME_GENERATOR、ResourceLoader、ClassLoader、类型转换器ConversionService
applyInitializers(context); //执行初始化器
listeners.contextPrepared(context); //通过EventPublishingRunListener发起上下文准备完毕事件ApplicationContextInitializedEvent
bootstrapContext.close(context); //关闭引导上下文,发起BootstrapContextClosedEvent事件,默认没有监听器来监听此事件
if (this.logStartupInfo) {//打印启动日志
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);//设置是否允许循环引用
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);//设置是否bean注入是否支持覆盖
}
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); //是否懒初始化
}
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
// Load the sources
Set<Object> sources = getAllSources();//加载所有资源
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));//注册Application类到上下文中
listeners.contextLoaded(context);//发布上下文已加载事件,这个也是ApplicationPreparedEvent事件,跟上面listeners.contextPrepared(context)执行的listener一样
}
初始化器的执行,现在springboot默认有以下几种初始化器:
org.springframework.boot.context.config.DelegatingApplicationContextInitializer:委派上下文初始化器,这个类本身不执行初始化动作,但是会加载context.initializer.classes配置的初始化器,可以执行自定义的上下文初始化器。
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer:创建一个共享的CachingMetadataReaderFactoryPostProcessor对象,添加到上下文的BeanFactoryPostProcessor中。
org.springframework.boot.context.ContextIdApplicationContextInitializer: 设置上下文ID,取值为spring.application.name,如果没有配置这个属性,默认为application。
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer: 添加一个ConfigurationWarningsPostProcessor到上下文的BeanFactoryPostProcessor中。
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer:RSocket服务器会用到,添加org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer.Listener.Listener(ConfigurableApplicationContext)到上下文的ApplicationListener中,监听RSocketServerInitializedEvent事件。
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer:添加一个监听WebServerInitializedEvent事件的ApplicationListener,用来设置本地服务端口号属性,server.port配置的那个。
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener:添加一个ConditionEvaluationReportListener到ApplicationListener中,用来打印ConditionEvaluationReport,需要日志DEBUG模式。
初始化器执行完紧接着就发布上下文已准备的事件,下面是支持ApplicationContextInitializedEvent事件的默认监听器:
org.springframework.boot.env.EnvironmentPostProcessorApplicationListener:这里就执行了一个逻辑,调用了deferredLogs的switchOverAll方法,暂不知这个逻辑到底做何用。
org.springframework.boot.context.logging.LoggingApplicationListener:注入日志系统springBootLoggingSystem,日志文件springBootLogFile,日志组springBootLoggerGroups,日志生命周期springBootLoggingLifecycle。
标题:springboot(2.4.1)源代码分析四prepareContext上下文准备
作者:michael
地址:https://blog.junxworks.cn/articles/2022/12/05/1670232739435.html