SpringBoot启动关键点解析 及启动日志追溯
Posted ybkback2018
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot启动关键点解析 及启动日志追溯相关的知识,希望对你有一定的参考价值。
<!doctype html>Spring Boot 源码阅读2
目录
目录1 SpringBoot启动关键点解析1.1 new SpringApplication(primarySources)部分1.2 run(args)部分1.2.1 ConfigurableEnvironment提供的服务(关注的信息)1.2.2 ConfigurableApplicationContext1.2.3 SpringApplication.prepareContext1.2.4 SpringApplication.refreshContext1.2.4.1 AbstractApplicationContext.finishBeanFactoryInitialization1.2.4.2 DefaultListableBeanFactory.preInstantiateSingletons1.2.5 默认的关闭钩子1.3 启动日志分析1.3.1 虚拟机启动日志打印1.3.2 Banner打印1.3.3 环境信息打印1.3.4 web服务启动日志1.3.5 实例化相关信息打印1.3.6 web启动打印1.3.7 启动成功日志
1 SpringBoot启动关键点解析
启动核心分为两部分new SpringApplication(primarySources)和执行run(args)方法,
1.1 new SpringApplication(primarySources)部分
部分的核心是从META/spring.facteries中读取ApplicationContextInitializer和ApplicationListener配置,然后直接通过反射实例化,实例化+排序完毕后,把应用初始化器ApplicationContextInitializer和应用监听放到SpringApplication对象上
1.2 run(args)部分
run部分最核心的构建ConfigurableApplicationContext这个上下文对象对象,构建完毕后当前线程是会返回的。
run方法实现为:
x
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);//获取SpringApplicationRunListener的监听,当前只有org.springframework.boot.context.event.EventPublishingRunListener一个
listeners.starting(); //调度监听的start方法,这里事件发布监听的start方法是发布了一个ApplicationStartingEvent事件
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//创建一个ConfigurableEnvironment(理解参见1.2.1),初始化
//让configurationProperties的属性源始终位于第一(应该是保证最高优先级)
//调度应用监听执行environmentPrepared, EventPublishingRunListener一个也就是发布一个ApplicationEnvironmentPreparedEvent事件
//将获取到的environment中的spring.main配置绑定到SpringApplication的source中(这部分用到了一个Binder语法,没有看懂)
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 从环境中读取spring.beaninfo.ignore并设置为系统属性
configureIgnoreBeanInfo(environment);
//Banner打印
Banner printedBanner = printBanner(environment);
//创建ConfigurableApplicationContext对象,这个上下文对象关注的信息有点多,参见(1.2.2)
context = createApplicationContext();
//从META_DATA/spring.facteries中读取SpringBootExceptionReporter的配置并进行实例化,默认读取出来是org.springframework.boot.diagnostics.FailureAnalyzers
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//准备环境,参见(1.2.3),主要为设置上下文对象的容器属性
//调度一开始读取的initializer的执行initialize方法,之后调度监听器的contextPrepared,发布ApplicationContextInitializedEvent
//打印开始和profile的日志
//把拿到的标签类进行beanDefinition注册,之后调度监听器的contextLoaded,发布ApplicationPreparedEvent
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//刷新上下文,参见(1.2.4),
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
//打印已启动信息以及耗时情况
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
//调度监听器的started的方法,此处默认为发布一个ApplicationStartedEvent事件
listeners.started(context);
//找注册的ApplicationRunner、CommandLineRunner,排序后分别调度对应的ApplicationRunner和CommandLineRunner (spring-boot的启动后自动执行建表语句好像就是通过这个机制实现。这里可以做一些启动后就需要立马执行的事)。注意,此时刚发布ApplicationStartedEvent而尚未发布ApplicationReadyEvent
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
//调度监听器的running方法,此处默认为发布一个ApplicationReadyEvent事件。
//执行完次应该代表服务正式可用
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
1.2.1 ConfigurableEnvironment提供的服务(关注的信息)
从环境接口的方法来看,它主要关注与当前应用的profile、propertySource、systemEnvironment、systemProperties、getConversionService;环境本身重要的信息有webApplicationType(ConversionService是干啥的??)
1.2.2 ConfigurableApplicationContext
从名字解读是可配置的应用容器对象。关注的内容非常多,包括应用监听器(ApplicationListener)、应用的后置处理器(PosProcessor)、应用的协议解析器(ProtocolResolver)、bean管理、类加载器、环境对象管理(Environment)、消息对象管理(Message)、资源对象管理(Resouce)等.
容器对象是根据应用类型有所不同的,SERVLET创建的是org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext的容器对象,该对象在构造时会构造一个AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner对象。
AnnotatedBeanDefinitionReader对象同时设置了beanFactory的dependencyComparator、autowireCandidateResolver实例,进行了ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、EventListenerMethodProcessor、DefaultEventListenerFactory的bean声明。
ClassPathBeanDefinitionScanner对象创建时同时TypeFilter的实例(包含AnnotationTypeFilter(Component.class))
1.2.3 SpringApplication.prepareContext
代码如下:
xxxxxxxxxx
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
//把SpringApplication上的部分信息绑定到context上
postProcessApplicationContext(context);
//拿到之前从配置中读取并实例化的initializer,执行initialize(context)方法 !!它们大部分都是给容器设置一些值
applyInitializers(context);
//调度监听器的contextPrepared,此处为发布一个ApplicationContextInitializedEvent事件
listeners.contextPrepared(context);
if (this.logStartupInfo) {
//打印应用启动的日志
logStartupInfo(context.getParent() == null);
//打印profile加载情况
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//把ApplicationArguments注册成单例bean
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
//如果Banner非空,也注册成单例bean
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
//设置bean工程的allowBeanDefinitionOverriding属性
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
//如果是lazyInitialization模式(默认为false),给上下文追加一个LazyInitializationBeanFactoryPostProcessor的后置处理器实例
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources -》注册的入口类被识别为私有源,需要加入更多的标签类看看是否是在这里就已经被全部识别
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//把识别出来的源都进行beanDefinition注册
load(context, sources.toArray(new Object[0]));
//调度监听器的contextLoaded方法,这里表现为发布一个ApplicationPreparedEvent事件
listeners.contextLoaded(context);
}
默认读取并实例化的初始化器有:
0 = {DelegatingApplicationContextInitializer@3271} 1 = {SharedMetadataReaderFactoryContextInitializer@3272} 2 = {ContextIdApplicationContextInitializer@3273} 3 = {ConfigurationWarningsApplicationContextInitializer@3274} 4 = {RSocketPortInfoApplicationContextInitializer@3275} 5 = {ServerPortInfoApplicationContextInitializer@3276} 6 = {ConditionEvaluationReportLoggingListener@3277}
1.2.4 SpringApplication.refreshContext
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
//注册关闭虚拟机的钩子
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
//AbstractApplicationContext.refresh
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing. //初始化当前容器的一些属性
prepareRefresh();
// Tell the subclass to refresh the internal bean factory. //设置工厂的序列化id
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//初始化beanFactory的一些属性,创建一些实例类,也注册了几个beanDefinition
//设置内容包括 beanClassLoader、StandardBeanExpressionResolver、ResourceEditorRegistrar、ApplicationContextAwareProcessor
//设置忽略的依赖接口EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware
//注册BeanFactory(SpringApplication)、ResourceLoader(ConfigurableApplicationContext)、ApplicationEventPublisher(ConfigurableApplicationContext)、ApplicationContext(ConfigurableApplicationContext)
//追加beanPostProcessors:ApplicationListenerDetector
//管控environment、systemProperties、systemEnvironment单例
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//设置一个WebApplicationContextServletContextAwareProcessor后置处理器
//设置忽略接口依赖ServletContextAware
//注册并实例化register和session的Scope,在注册过程中通过WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());跳转到sprig-web中
//注册ServletRequest、ServletResponse、HttpSession、WebRequest的解析以来
//!!!注意,也就这里引入了对于spring-web的支持 (spring-boot通过spring-boot-starter..等是引入了spring-web的...)
//这里总结就是注册了spring-web相关的信息
postProcessBeanFactory(beanFactory);
 以上是关于SpringBoot启动关键点解析 及启动日志追溯的主要内容,如果未能解决你的问题,请参考以下文章