一、整体过程说明
1.1 启动入口方法
SpringApplication.run(LoySpringBootApplication.class,args);
1.2 总体过程说明
- 1.获取并启动监听器
- 2.构建容器环境
- 3.创建容器
- 4.实例化SpringBootExceptionReporter,用于支持报告异常的错误
- 5.准备容器
- 6.刷新容器
- 7.刷新容器后的扩展接口
1.3 整体过程源码
/**
* 运行一个spring应用,创建并刷新一个ApplicationContext
*/
public ConfigurableApplicationContext run(String... args) {
// 时间监控
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 获取Spring.factories中的监听器变量,args为指定的参数数组,默认为SpringApplication
// 1.获取并启动监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 2.构建容器环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
// 设置需要忽略的bean
configureIgnoreBeanInfo(environment);
// banner的打印控制
Banner printedBanner = printBanner(environment);
// 3.创建容器
context = createApplicationContext();
// 4.实例化SpringBootExceptionReporter,用于支持报告异常的错误
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 5.准备容器
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
// 6. 刷新容器
refreshContext(context);
// 7.刷新容器后的扩展接口
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
二、源码分析
2.1.1 getRunListeners(args)获取并启动监听器
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
在获取监听器的方法中,getSpringFactoriesInstances(SpringApplictionRunListener.class, types, this,args)将当前对象作为参数,该方法用来获取spring.factories对应的监听器
org.springframework.boot.SpringApplicationRunListener=
\org.springframework.boot.context.event.EventPublishingRunListener
2.1.2 listeners.starting()启动监听器
// 启动监听器
listeners.starting();
// 实现方法 SpringApplicationRunListeners
public void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
// 最终调用方法 EventPublishingRunListener
@Override
public void starting() {
// 这里是创建application启动事件“ApplicationStartingEvent”
this.initialMulticaster.multicastEvent(
new ApplicationStartingEvent(this.application, this.args));
}
EventPublishingRunListener
这个是SpringBoot框架中最早执行的监听器,在该监听器执行started()方法时,会继续发布事件,也就是事件传递,这种实现主要还是基于Spring的事件机制。
2.2.1 prepareEnvironment(listeners,applicationArguments) 构建容器环境
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 获取对应的ConfigurableEnvironment
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 发布环境已准备事件,这是第二次发布事件
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (this.webApplicationType == WebApplicationType.NONE) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
ConfigurationPropertySources.attach(environment);
return environment;
}
Environment
接口提供了4种实现方式,StandardEnvironment
、StandardServletEnvironment
和MockEnvironment
、StandardReactiveWebEnvironment
,分别代表普通程序、Web程序、测试程序的环境、响应式web环境
2.3.1 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) {
...
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
这里创建容器的类型 还是根据webApplicationType进行判断的。
2.4.1 实例化SpringBootExceptionReporter,用于支持报告异常的错误
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
这里还是以同样的方式获取 spring.factories文件中的指定类。
org.springframework.boot.SpringBootExceptionReporter=
\org.springframework.boot.diagnostics.FailureAnalyzers
该类主要是在项目启动失败之后,打印log:
private void reportFailure(Collection<SpringBootExceptionReporter> exceptionReporters,
Throwable failure) {
try {
for (SpringBootExceptionReporter reporter : exceptionReporters) {
if (reporter.reportException(failure)) {
//上报错误log
registerLoggedException(failure);
return;
}
}
}
catch (Throwable ex) {
// Continue with normal handling of the original failure
}
if (logger.isErrorEnabled()) {
logger.error("Application run failed", failure);
registerLoggedException(failure);
}
}
2.5.1 prepareContext() 准备容器
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//设置容器环境,包括各种变量
context.setEnvironment(environment);
//执行容器后置处理(分析在2.5.2)
postProcessApplicationContext(context);
//执行容器中的ApplicationContextInitializer(包括 spring.factories和自定义的实例)
applyInitializers(context);
//发送容器已经准备好的事件,通知各监听器
listeners.contextPrepared(context);
//打印log
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
//注册启动参数bean,这里将容器指定的参数封装成bean,注入容器
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
//设置banner
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
//获取我们的启动类指定的参数,可以是多个
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//加载我们的启动类,将启动类注入容器(分析在2.5.3)
load(context, sources.toArray(new Object[0]));
//发布容器已加载事件。
listeners.contextLoaded(context);
}
2.5.2 容器的后置处理
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
if (this.beanNameGenerator != null) {
context.getBeanFactory().registerSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
}
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
((GenericApplicationContext) context)
.setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader) context)
.setClassLoader(this.resourceLoader.getClassLoader());
}
}
}
这里默认不执行任何逻辑,因为beanNameGenerator和resourceLoader默认为空。之所以这样做,是springBoot留给我们的扩展处理方式,类似于这样的扩展,spring中也有很多
2.5.3 加载启动指定类
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();
}
// 实际调用
private int load(Class<?> source) {
if (isGroovyPresent()
&& GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
GroovyBeanDefinitionSource.class);
load(loader);
}
if (isComponent(source)) {
//以注解的方式,将启动类bean信息存入beanDefinitionMap
this.annotatedReader.register(source);
return 1;
}
return 0;
}
这里参数即为我们项目启动时传递的参数:SpringApplication.run(SpringBootApplication.class, args);
由于我们指定了启动类,所以上面也就是加载启动类到容器。
2.6.1 refreshContext(context) 刷新容器
synchronized (this.startupShutdownMonitor) {
// 刷新上下文环境
prepareRefresh();
// 初始化BeanFactory,解析XML,相当于之前的XmlBeanFactory的操
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 为上下文准备BeanFactory,即对BeanFactory的各种功能进行填充,
prepareBeanFactory(beanFactory);
try {
// 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
postProcessBeanFactory(beanFactory);
// 激活各种BeanFactory处理器,包括BeanDefinitionRegistryBeanFactoryPostProcessor和普通的BeanFactoryPostProcessor
// 执行对应的postProcessBeanDefinitionRegistry方法 和 postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(beanFactory);
// 注册拦截Bean创建的Bean处理器,即注册BeanPostProcessor,不是BeanFactoryPostProcessor
registerBeanPostProcessors(beanFactory);
// 初始化上下文中的资源文件,如国际化文件的处理等
initMessageSource();
// 初始化上下文事件广播器,并放入applicatioEventMulticaster,如ApplicationEventPublisher
initApplicationEventMulticaster();
// 给子类扩展初始化其他Bean
onRefresh();
// 在所有bean中查找listener bean,然后注册到广播器中
registerListeners();
/**
* 设置转换器
* 注册一个默认的属性值解析器
* 冻结所有的bean定义,说明注册的bean定义将不能被修改或进一步的处理
* 初始化剩余的非惰性的bean,即初始化非延迟加载的bean
*/
finishBeanFactoryInitialization(beanFactory);
// 完成初始化,通知生命周期处理器lifeCycleProcessor刷新过程,同时发出ContextRefreshEvent通知其他人
finishRefresh();
}
catch (BeansException ex) {
...
}
finally {
// 重置缓存
resetCommonCaches();
}
}
2.7.1 afterRefresh 刷新容器后的扩展接口
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
}
扩展接口,设计模式中的模板方法,默认为空实现。如果有自定义需求,可以重写该方法。比如打印一些启动结束log,或者一些其它后置处理。