雷丰阳springboot之原理运行流程
作者:互联网
- 雷丰阳课件
- 引子-重要的监听器
- Debug跟踪springboot启动
- 第一步:创建SpringApplication对象
- 番外1:判断web环境
- 番外2:从类路径下找Initializer
- 番外3:从类路径下找到ApplicationListener
- 番外4:找到主配置类
- 第二步:运行run方法
- 运行流程
- 番外1:configureHeadlessProperty是跟做awt应用有关的玩意
- 番外2:SpringApplicationRunListeners
- 番外3:prepareEnvironment
- 番外4:printBanner
- 番外5:createApplicationContext()
- 番外6:prepareContext
- 番外7:refreshContext()
- 番外8:afterRefresh()
雷丰阳课件
引子-重要的监听器
springboot的运行流程是非常复杂的。
但是在运行流程当中,包含了几个非常重要的事件回调机制。
我们也希望掌握这些事件回调机制,真正干预到springboot的运行流程。
特别是这些事件回调机制,牵扯到的接口。
ApplicationContextInitializer
,需要配置在META-INF/spring-factoriesSpringApplicationRunListener
,需要配置在META-INF/spring-factories- ApplicationRunner,需要放在IOC容器中。
- CommandLineRunner,需要放在IOC容器中。
Debug跟踪springboot启动
step into
step into
这里说明了springboot启动是分为两步,第一步是创建SpringApplication对象,第二步是运行run方法。
第一步:创建SpringApplication对象
step into
step over
不断step over,就来到了下面:
这是说明,是调用了initialize(sources)
来创建对象的。
step into
通过initialize(sources)
创建对象的流程,就是下面的流程:
private void initialize(Object[] sources) {
//sources就是主配置类,这里面就是sources不为空的时候,保存主配置类。
//保存在了sources属性当中。
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
//判断当前应用是不是web应用,具体怎么判断,看下一个番外1
this.webEnvironment = deduceWebEnvironment();
//参考番外2
//getSpringFactoriesInstances方法从类路径下找到"META-INF/spring.factories"下面配置的所有的ApplicationContextInitializer,然后保存起来。
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//从类路径下找到"META-INF/spring.factories"下面配置的所有的ApplicationListener
//参考番外3
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//参考番外4
//决定哪个applicationClass是个主程序。
//从多个配置类中找到有main方法的主配置类
this.mainApplicationClass = deduceMainApplicationClass();
}
到这里的时候,springapplication对象,就创建完成了。
番外1:判断web环境
判断web环境的时候,是这样的:
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
看看上面的Servlet
或者ConfigurableWebApplicationContext
这些东西是否存在。
番外2:从类路径下找Initializer
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
这句话的意思就是:
getSpringFactoriesInstances方法从"META-INF/spring.factories"下面找ApplicationContextInitializer
这些东西就在这里:
我们step over一下,然后点进去看看,找到了多少initializer:
一看是找到了6个Initializer。
番外3:从类路径下找到ApplicationListener
一共是找到了10个listeners。
番外4:找到主配置类
this.mainApplicationClass = deduceMainApplicationClass();
从多个配置类中找到有main方法的主配置类。
第二步:运行run方法
运行流程
public ConfigurableApplicationContext run(String... args) {
// 创建一个监听,然后启动
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//创建一个IOC容器,是空的。
//声明analyzers
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
//参考番外1
//configureHeadlessProperty是跟做awt应用有关的玩意
configureHeadlessProperty();
//获取SpringApplicationRunListeners,从类路径META-INF/spring.factories
//参考番外2
SpringApplicationRunListeners listeners = getRunListeners(args);
//回调所有的SpringApplicationRunListeners的starting方法。
//参考番外2
listeners.starting();
try {
//把args命令行参数,用ApplicationArguments封装了一下。
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//参考番外3
//创建环境,然后回调所有的SpringApplicationRunListeners的environmentPrepared方法。
//表示环境准备完成。
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//控制台打印Banner图标
//参考番外4
Banner printedBanner = printBanner(environment);
//创建IOC容器,ApplicationContext
//参考番外5
//决定创建web的IOC还是普通的IOC容器
context = createApplicationContext();
//analyzers主要是出现异常之后,用来做异常报告的。
analyzers = new FailureAnalyzers(context);
//参考番外6
//准备上下文环境,传入了IOC容器,环境,listeners等等
//applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法
//回调所有的SpringApplicationRunListener的contextPrepared()方法。
//prepareContext运行完成之后,回调所有的SpringApplicationRunListener的contextLoaded()
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//参考番外7
//刷新容器:IOC容器初始化的过程。
//加载IOC容器当中所有的组件。
//扫描所有的配置类,扫描所有的@Bean来创建对象进行初始化
//如果是web应用,还会创建嵌入式的tomcat
//扫描,创建,加载所有组件的地方
//自动配置类,组件,配置类,都是在这里,IOC容器加载的。
refreshContext(context);
//参考番外8
//从IOC容器中获取所有的ApplicationRunner和CommandLineRunner
//ApplicationRunner先回调。
//CommandLineRunner再回调。
afterRefresh(context, applicationArguments);
//所有的SpringApplicationRunListener回调finished方法
listeners.finished(context, null);
//保存当前应用状态
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//整个springboot应用启动完成之后。
//返回IOC容器
//IOC容器当中有所有的组件。
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
番外1:configureHeadlessProperty是跟做awt应用有关的玩意
番外2:SpringApplicationRunListeners
一路step over然后可以看到:获取到的listener是如下:
从listeners.starting();
step into进来
点进去,可以看到SpringApplicationRunListener当中,有下面的回调机制的方法:
番外3:prepareEnvironment
首先是创建环境
创建环境完成后,会回调SpringApplicationRunListeners的environmentPrepared方法。
番外4:printBanner
番外5:createApplicationContext()
step into之后,看到下面的内容:
番外6:prepareContext
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//将environment保存到IOC容器当中。
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
// 把命令行参数的对象,注册到IOC容器中。包括把banner也注册进来。
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()]));
// 回调所有的contextLoaded方法。
listeners.contextLoaded(context);
}
applyInitializers(context);
applyInitializers是干嘛的呢?这些应该跟一些初始化器有关。
我们step into进去。
获取所有的ApplicationContextInitializer,调用他们的initialize方法。
这些ApplicationContextInitializer,就是我们在第一步,创建SpringApplication对象的时候,拿到的所有的ApplicationContextInitializer。
listeners.contextPrepared(context);
番外7:refreshContext()
不断step into,来到这里:
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
//初始化容器中所有的单实例的bean。
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
番外8:afterRefresh()
step into进来。
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
callRunners(context, args);
}
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<Object>();
//相当于,从所有的IOC容器中,获取所有的ApplicationRunner和CommandLineRunner
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<Object>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
标签:springboot,番外,step,雷丰阳,sources,listeners,context,IOC,流程 来源: https://www.cnblogs.com/gnuzsx/p/14726188.html