目录
一、SpringApplication构造方法解析
1. web应用类型
2. BootstrapRegistryInitializer
3. ApplicationContextInitializer
4. ApplicationListener
5. 推断Main方法所在类
二、SpringApplication.run(String... args)方法解析
1.创建DefaultBootstrapContext
2.获取SpringApplicationRunListeners
3.调用SpringApplicationRunListener的starting()
4.创建和配置Environment
5.配置需要忽略的Bean
6.打印Banner
7.创建ApplicationContext(Spring容器)
8.准备ApplicationContext(Spring容器)
8.1 ApplicationContextInitializer初始化Spring容器
8.2 SpringApplicationRunListener的contextPrepared()
8.3 DefaultBootstrapContext调用close()
8.4 load()方法将启动类作为配置类注册到Spring容器
8.5 SpringApplicationRunListener的contextLoaded()
9. 刷新ApplicationContext(Spring容器)
10. SpringApplicationRunListener的started()
11. 执行Runners
12. SpringApplicationRunListener的running()
13. 出现异常执行SpringApplicationRunListener的failed()
一、SpringApplication构造方法解析
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
1. web应用类型
private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
如果项目依赖中存在org.springframework.web.reactive.DispatcherHandler,同时不存在org.springframework.web.servlet.DispatcherServlet,那么应用类型为WebApplicationType.REACTIVE
如果项目依赖中不存在org.springframework.web.reactive.DispatcherHandler,同时也不存在org.springframework.web.servlet.DispatcherServlet,那么应用类型为WebApplicationType.NONE
否则,应用类型为WebApplicationType.SERVLET
2. BootstrapRegistryInitializer
从META-INF/spring.factories中读取键值为BootstrapRegistryInitializer类型的扩展点,并实例化出对应扩展对象实例
BootstrapRegistryInitializer的作用是可以初始化BootstrapRegistry
BootstrapRegistry时一个简单的对象注册表,在启动和 Environment 处理期间可用,直到准备完成 ApplicationContext(Spring 容器) 为止。可用于注册创建实例,或者完成ApplicationContext (Spring 容器)后共享一些实例
3. ApplicationContextInitializer
从META-INF/spring.factories中读取键值为ApplicationContextInitializer类型的扩展点,并实例化出对应扩展对象实例
ApplicationContextInitializer是用来初始化Spring容器ApplicationContext对象的,比如可以利用ApplicationContextInitializer来向Spring容器中添加ApplicationListener
4. ApplicationListener
从"META-INF/spring.factories"中读取键值为ApplicationListener类型的扩展点,并实例化出对应扩展对象
5. 推断Main方法所在类
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
根据当前线程的调用栈来判断main()方法在哪个类,哪个类就是Main类。
二、SpringApplication.run(String... args)方法解析
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
listeners.started(context, timeTakenToStartup);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
1.创建DefaultBootstrapContext
使用SpringApplication构造方法中创建的BootstrapRegistryInitializer初始化DefaultBootstrapContext对象
2.获取SpringApplicationRunListeners
从"META-INF/spring.factories"中读取键值为SpringApplicationRunListeners类型的扩展点,并实例化出对应扩展对象
3.调用SpringApplicationRunListener的starting()
SpringBoot默认提供了一个EventPublishingRunListener,它实现了SpringApplicationRunListener接口,默认情况下会利用EventPublishingRunListener发布一个ApplicationStartingEvent事件,可以通过定义ApplicationListener来消费监听这个事件
4.创建和配置Environment
Environment对象表示环境变量,该对象内部主要包含了:操作系统环境变量、JVM配置信息、-D方式所配置的JVM环境变量
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
listeners.environmentPrepared(bootstrapContext, environment);
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
SpringApplicationRunListener的environmentPrepared()
默认情况下会利用EventPublishingRunListener发布一个ApplicationEnvironmentPreparedEvent事件,可以通过定义ApplicationListener来消费这个事件,比如默认情况下会有一个EnvironmentPostProcessorApplicationListener来消费这个事件,而这个ApplicationListener接收到这个事件之后,就会解析application.properties、application.yml文件并添加到Environment对象中。
5.配置需要忽略的Bean
public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore";
private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
Boolean ignore = environment.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME,
Boolean.class, Boolean.TRUE);
System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString());
}
}
6.打印Banner
SpringApplicationBannerPrinter
7.创建ApplicationContext(Spring容器)
使用ApplicationContextFactory.DEFAULT根据应用类型创建对应的Spring容器
public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
return (webApplicationType != WebApplicationType.SERVLET) ? null
: new AnnotationConfigServletWebServerApplicationContext();
}
应用类型为SERVLET,则对应AnnotationConfigServletWebServerApplicationContext
应用类型为REACTIVE,则对应AnnotationConfigReactiveWebServerApplicationContext
应用类型为普通类型,则对应AnnotationConfigApplicationContext
一般使用的应用类型为SERVLET:AnnotationConfigServletWebServerApplicationContext
8.准备ApplicationContext(Spring容器)
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
bootstrapContext.close(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
// 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);
}
8.1 ApplicationContextInitializer初始化Spring容器
默认SpringBoot提供了多个ApplicationContextInitializer,其中比较重要的有ConditionEvaluationReportLoggingListener
@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
this.report = ConditionEvaluationReport.get(this.applicationContext.getBeanFactory());
}
}
在该类的initialize()方法中:
将Spring容器赋值给它的applicationContext属性
并且往Spring容器中添加一个ConditionEvaluationReportListener(ConditionEvaluationReportLoggingListener的内部类),它是一个ApplicationListener
并生成一个ConditionEvaluationReport对象赋值给它的report属性
ConditionEvaluationReportListener会负责接收ContextRefreshedEvent事件,也就是Spring容器启动完毕就会触发ContextRefreshedEvent,ConditionEvaluationReportListener就会打印自动配置类的条件评估报告。
protected void onApplicationEvent(ApplicationEvent event) {
ConfigurableApplicationContext initializerApplicationContext = this.applicationContext;
if (event instanceof ContextRefreshedEvent) {
if (((ApplicationContextEvent) event).getApplicationContext() == initializerApplicationContext) {
logAutoConfigurationReport();
}
}
else if (event instanceof ApplicationFailedEvent
&& ((ApplicationFailedEvent) event).getApplicationContext() == initializerApplicationContext) {
logAutoConfigurationReport(true);
}
}
8.2 SpringApplicationRunListener的contextPrepared()
默认会利用EventPublishingRunListener发布一个ApplicationContextInitializedEvent事件,默认情况没有ApplicationListener消费该事件
8.3 DefaultBootstrapContext调用close()
关闭时要调用BootstrapContext的方法
8.4 load()方法将启动类作为配置类注册到Spring容器
8.5 SpringApplicationRunListener的contextLoaded()
默认会利用EventPublishingRunListener发布一个ApplicationPreparedEvent事件
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
for (ApplicationListener<?> listener : this.application.getListeners()) {
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
context.addApplicationListener(listener);
}
this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
9. 刷新ApplicationContext(Spring容器)
调用Spring容器的refresh()方法:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
contextRefresh.end();
}
}
}
ServletWebServerApplicationContext在重写onRefresh方法,在该方法中创建了WebServer,默认启动Tomcat服务器。
@Override
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
10. SpringApplicationRunListener的started()
发布ApplicationStartedEvent事件和AvailabilityChangeEvent事件,AvailabilityChangeEvent事件表示状态变更状态,变更后的状态为LivenessState.CORRECT
@Override
public void started(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
}
public enum LivenessState implements AvailabilityState {
/**
* The application is running and its internal state is correct.
*/
CORRECT,
/**
* The application is running but its internal state is broken.
*/
BROKEN
}
11. 执行Runners
获取Spring容器中的ApplicationRunner和CommandLineRunner类型的Bean,然后按顺序调用他们的run()方法
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
12. SpringApplicationRunListener的running()
发布ApplicationReadyEvent事件和AvailabilityChangeEvent事件,AvailabilityChangeEvent事件表示状态变更状态,变更后的状态为ReadinessState.ACCEPTING_TRAFFIC
@Override
public void running(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
}
public enum ReadinessState implements AvailabilityState {
/**
* The application is ready to receive traffic.
*/
ACCEPTING_TRAFFIC,
/**
* The application is not willing to receive traffic.
*/
REFUSING_TRAFFIC
}
13. 出现异常执行SpringApplicationRunListener的failed()
发布ApplicationFailedEvent事件
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);
if (context != null && context.isActive()) {
// Listeners have been registered to the application context so we should
// use it at this point if we can
context.publishEvent(event);
}
else {
// An inactive context may not have a multicaster so we use our multicaster to
// call all of the context's listeners instead
if (context instanceof AbstractApplicationContext) {
for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
.getApplicationListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
this.initialMulticaster.multicastEvent(event);
}
}
至此Springboot的启动执行流程全部完成。