springboot(2.4.1)源代码分析四prepareContext上下文准备

  |   0 评论   |   0 浏览

1602950199025774592.png

  上一篇讲了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