SpringBoot启动时都做了哪些事(三)?

关联博文:
SpringBoot启动时都做了哪些事(一)?
SpringBoot启动时都做了哪些事(二)?
SpringBoot启动时都做了哪些事(三)?
SpringBoot启动时都做了哪些事(四)?

接上一篇SpringBoot启动时都做了哪些事(二)?后,我们继续分析SpringBoot启动过程流程。

本文我们开始分析应用上下文的创建和配置。核心流程梳理如下:

  • 创建应用上下文实例AnnotationConfigServletWebServerApplicationContext,这里会同步创建AnnotatedBeanDefinitionReaderClassPathBeanDefinitionScanner并注册一系列"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);
}

AnnotatedBeanDefinitionReaderClassPathBeanDefinitionScanner的替代方案,用来显示注册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场景
  • DefaultEventListenerFactoryEventListenerMethodProcessor 支持 @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方法并广播ApplicationContextInitializedEventApplicationPreparedEvent事件。

// 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注册应用主类,也就是注册BeanDefinitionbeanDefinitionMap中并记录beanNamebeanDefinitionNames中。
在这里插入图片描述

⑤ listeners.contextLoaded

如下所示,这里实际上会触发EventPublishingRunListenercontextLoaded方法。

void contextLoaded(ConfigurableApplicationContext context) {
	for (SpringApplicationRunListener listener : this.listeners) {
		listener.contextLoaded(context);
	}
}

this.application指的是SpringApplication实例。这个方法会将SpringApplication中的ApplicationListener添加到ConfigurableApplicationContextapplicationListeners中。如果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} 

到此,我们广播了ApplicationStartingEventApplicationEnvironmentPreparedEventApplicationContextInitializedEvent以及ApplicationPreparedEvent事件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流烟默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值