目录
2.1获取run方法的监听器EventPublishingRunListener
2.3创建容器:createApplicationContext()
2.4获取SpringBootExceptionReporter
1SpringApplication初始化
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//判断web环境:NONE、SERVLET、REACTIVE
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//从Spring.factories加载Initializer
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//从Spring.factories加载监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//获取主类
this.mainApplicationClass = deduceMainApplicationClass();
}
2run()
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
/第一步:获取run方法的监听器EventPublishingRunListener,负责发布run方法中的事件
SpringApplicationRunListeners listeners = getRunListeners(args);
/发布starting事件
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
/第二步:构造容器环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
/设置需要忽略的bean
configureIgnoreBeanInfo(environment);
/打印banner
Banner printedBanner = printBanner(environment);
/第三步:创建容器
context = createApplicationContext();
/第四步:实例化SpringBootExceptionReporter.class,用来支持报告关于启动的错误
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
/第五步:准备容器
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
/第六步:刷新容器
refreshContext(context);
/第七步:刷新容器后的扩展接口
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获取run方法的监听器EventPublishingRunListener
从spring.factories获取SpringApplicationRunListener的实现类EventPublishingRunListener,负责发布run方法中的事件,在run方法执行过程中触发监听器执行相应逻辑。
EventPublishingRunListener通过持有SimpleApplicationEventMulticaster对象,广播事件,遍历监听器执行相应方法。
public interface SpringApplicationRunListener {
void starting();
void environmentPrepared(ConfigurableEnvironment environment);
void contextPrepared(ConfigurableApplicationContext context);
void contextLoaded(ConfigurableApplicationContext context);
void started(ConfigurableApplicationContext context);
void running(ConfigurableApplicationContext context);
void failed(ConfigurableApplicationContext context, Throwable exception);
}
2.2准备环境:prepareEnvironment()
加载外部化配置资源到environment,包括命令行参数、servletConfigInitParams、servletContextInitParams、systemProperties、sytemEnvironment、random、application.yml(.yaml/.xml/.properties)等;初始化日志系统。
2.3创建容器: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);
}
根据webApplicationType进行判断,创建对应类型容器。
2.4获取SpringBootExceptionReporter
从spring.factories获取,用来支持报告关于启动的错误
该类主要是在项目启动失败之后,打印log
2.5准备容器prepareContext()
这一步主要是在refresh()之前的准备动作。包含一个非常关键的操作:将启动类注入容器,为后续开启自动化配置奠定基础。
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//设置容器环境,包括各种变量
context.setEnvironment(environment);
//执行容器后置处理
postProcessApplicationContext(context);
//执行容器中的ApplicationContextInitializer(包括 spring.factories和自定义的实例)
applyInitializers(context);
//发送容器已经准备好的事件,通知各监听器
listeners.contextPrepared(context);
//打印log
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
//注册启动参数bean,这里将容器指定的参数封装成bean,注入容器
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
//设置banner
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
//获取我们的启动类指定的参数,可以是多个
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//加载我们的启动类,将启动类注入容器
load(context, sources.toArray(new Object[0]));
//发布容器已加载事件。
listeners.contextLoaded(context);
}
applyInitializers(context):
ApplicationContextInitializer是Spring框架原有的概念, 这个类的主要目的就是在 ConfigurableApplicationContext类型(或者子类型)的ApplicationContext做refresh之前,允许我们 对ConfigurableApplicationContext的实例做进一步的设置或者处理(加入beanFactoryPostProcessor)。
举例:
context.addBeanFactoryPostProcessor( new ConfigurationWarningsPostProcessor(getChecks()));
load(context, sources.toArray(new Object[0])):
这里会将我们的启动类加载到spring容器beanDefinitionMap中,为后续springBoot 自动化配置奠定基础,springBoot为我们提供的各种注解配置也与此有关。
2.6refresh
参考spring文章中的源码分析
参考: