问题:springboot启动入口都是一个run方法,这后面到底有哪些步骤呢?
SpringApplication.run(MyBlogApplication.class, args);
进入断点我们来查看一下:
1、首先进入SpringApplication类
/**
* Static helper that can be used to run a {@link SpringApplication} from the
* specified source using default settings.
* @param primarySource the primary source to load
* @param args the application arguments (usually passed from a Java main method)
* @return the running {@link ApplicationContext}
*/
public static ConfigurableApplicationContext run(Class<?> primarySource,
String... args) {
return run(new Class<?>[] { primarySource }, args);
}
2、run方法如下
/**
* Static helper that can be used to run a {@link SpringApplication} from the
* specified sources using default settings and user supplied arguments.
* @param primarySources the primary sources to load
* @param args the application arguments (usually passed from a Java main method)
* @return the running {@link ApplicationContext}
*/
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
return new SpringApplication(primarySources).run(args);
}
3、再来看看SpringApplication的构造方法
/**
* 创建一个SpringApplication 实例
* Create a new {@link SpringApplication} instance. The application context will load
* beans from the specified primary sources (see {@link SpringApplication class-level}
* documentation for details. The instance can be customized before calling
* {@link #run(String...)}.
* @param primarySources the primary bean sources
* @see #run(Class, String[])
* @see #SpringApplication(ResourceLoader, Class...)
* @see #setSources(Set)
*/
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
4、构造方法实现如下
/**
* 创建一个SpringApplication 实例
* Create a new {@link SpringApplication} instance. The application context will load
* beans from the specified primary sources (see {@link SpringApplication class-level}
* documentation for details. The instance can be customized before calling
* {@link #run(String...)}.
* @param resourceLoader the resource loader to use
* @param primarySources the primary bean sources
* @see #run(Class, String[])
* @see #setSources(Set)
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 这里resourceLoader为null。primarySources是run方法传入的启动类,这里可以有多个
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//应用类型,有三种属性值
//NONE:应用程序不应作为 Web 应用程序运行,也不应启动嵌入式 Web 服务器
//SERVLET:应用程序应作为基于 Servlet 的 Web 应用程序运行,并应启动嵌入式 Servlet Web 服务器。默认是SERVLET
//REACTIVE:应用程序应作为响应式 Web 应用程序运行,并应启动嵌入式响应式 Web 服务器
REACTIVE;
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//SPI机制通过clcassloader加载初始化工具
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
其中上下文初始化类列表(ApplicationContextInitializer)
[org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer, org.springframework.boot.context.ContextIdApplicationContextInitializer, org.springframework.boot.context.config.DelegatingApplicationContextInitializer, org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer, org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer, org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener]
应用监听初始化列表(ApplicationListener)
[org.springframework.boot.ClearCachesApplicationListener, org.springframework.boot.builder.ParentContextCloserApplicationListener, org.springframework.boot.context.FileEncodingApplicationListener, org.springframework.boot.context.config.AnsiOutputApplicationListener, org.springframework.boot.context.config.ConfigFileApplicationListener, org.springframework.boot.context.config.DelegatingApplicationListener, org.springframework.boot.context.logging.ClasspathLoggingApplicationListener, org.springframework.boot.context.logging.LoggingApplicationListener, org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener, org.springframework.boot.autoconfigure.BackgroundPreinitializer]
5、回到第2步,构造方法完成后执行run方法
/**
* 运行 Spring 应用程序,创建并刷新新的 ApplicationContext。
* 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<>();
// 设置Headless属性:java.awt.headless
configureHeadlessProperty();
//获取运行监听器集合,并启动监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
//创建并配置当前SpringBoot应用将要使用的Environment(包括配置要使用的PropertySource以及Profile),
//并遍历调用所有的SpringApplicationRunListener的environmentPrepared()方法,广播Environment准备完毕
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
// 根据环境信息输出Banner
Banner printedBanner = printBanner(environment);
// 创建 ApplicationContext 的策略方法,根据WebApplicationType的值来决定创建何种类型的ApplicationContext对象
context = createApplicationContext();
//SPI实现,根据SpringBootExceptionReporter类名,去找到所有META-INF/spring.factories的jar包,获取该类(根据当前类名,去找到所有META-INF/spring.factories的jar包,
// 获取该类名为key值的value值,然后返回根据@order注解排序后的实例化集合。
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);
}
// 调用所有的SpringApplicationRunListener的started()方法,广播SpringBoot已经完成了ApplicationContext初始化的全部过程。
listeners.started(context);
// 遍历所有注册的ApplicationRunner和CommandLineRunner,并执行其run()方法。
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// 调用所有的SpringApplicationRunListener的running()方法,广播SpringBoot已经可以处理服务请求了。
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
此处SPI实现初始化的类
[org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer@73a8da0f, org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer@50dfbc58, org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer@4416d64f, org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer@6bf08014, org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer@5e3d57c7, org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer@732d0d24, org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer@1fb19a0, org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer@6ee4d9ab, org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer@5a5338df, org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer@418c5a9c, org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer@18e36d14, org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer@5082d622, org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer@13d4992d, org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer@302f7971, org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer@332729ad, org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer@75d2da2d, org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer@4278284b, org.springframework.boot.actuate.autoconfigure.metrics.MissingRequiredConfigurationFailureAnalyzer@9573584]
6、准备上下文实现
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// 环境信息设置 StandardServletEnvironment {activeProfiles=[], defaultProfiles=[default], propertySources=[ConfigurationPropertySourcesPropertySource {name='configurationProperties'}, StubPropertySource {name='servletConfigInitParams'}, StubPropertySource {name='servletContextInitParams'}, MapPropertySource {name='systemProperties'}, OriginAwareSystemEnvironmentPropertySource {name='systemEnvironment'}, RandomValuePropertySource {name='random'}, OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/application.properties]'}]}
context.setEnvironment(environment);
postProcessApplicationContext(context);
// 在刷新上下文之前,将任何 ApplicationContextInitializers 应用于上下文。
applyInitializers(context);
// 发送事件
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 注册bean到spring容器中beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 加载启动类,如果被@Component注解修饰,加到bean定义的map中
load(context, sources.toArray(new Object[0]));
// 发送事件
listeners.contextLoaded(context);
}
7、遍历Runner,并执行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);
}
}
}