8-SpringBoot运行流程分析
优质
小牛编辑
129浏览
2023-12-01
8.1 SpringBoot入口
package com.clsaa.edu.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class App {
public static void main(String[] args) {
//第一种方法:实例化SpringApplication对象,然后调用run方法
/*
SpringApplication app = new SpringApplication(App.class);
ConfigurableApplicationContext context = app.run(args);
*/
//第二种方法:直接调用静态run方法
ConfigurableApplicationContext context = SpringApplication.run(App.class,args);
context.close();
}
}
8.1.1 静态调用run方法
- 可以看到静态调用run方法,内部是实例化了一个application对象再次调用run方法
/**
* Static helper that can be used to run a {@link SpringApplication} from the
* specified sources using default settings and user supplied arguments.
* @param sources the sources to load
* @param args the application arguments (usually passed from a Java main method)
* @return the running {@link ApplicationContext}
*/
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
8.1.2 application对象调用run方法
- Application对象的创建
/**
* Create a new {@link SpringApplication} instance. The application context will load
* beans from the specified sources (see {@link SpringApplication class-level}
* documentation for details. The instance can be customized before calling
* {@link #run(String...)}.
* @param sources the bean sources
* @see #run(Object, String[])
* @see #SpringApplication(ResourceLoader, Object...)
*/
public SpringApplication(Object... sources) {
initialize(sources);
}
- 初始化的一些判断
- 先判断是不是web环境
- 加载所有classpath下面的META-INF/spring.factories ApplicationInitializer
- 加载所有classpath下面的META-INF/spring.factories ApplicationListener
- 推断main方法所在的类
- 开始执行run方法
@SuppressWarnings({ "unchecked", "rawtypes" })
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webEnvironment = deduceWebEnvironment();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
private boolean deduceWebEnvironment() {
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return false;
}
}
return true;
}
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
- 执行run方法
- 设置java.awt.headless系统变量
- 加载所有classpath下面的META-INF/spring.factories 加载SpringApplicationRunListeners
- 执行所有listener的start方法
- 实例化ApplicationArguments
- 创建ConfigurableEnvironment
- 配置ConfigurableEnvironment,主要是把run方法的一些参数传递进去
- 执行SpringApplicationRunListeners的environmentPrepared(发布一个事件)
- 如果不是web环境,但是是web的environment,就把这个web的environment转换成标准的environment
- 打印banner
- 初始化applicationcontext,如果是web环境,则实例化annotationFonfigEmbeddedWebApplicationContext对象否则实例化AnnotationConfigApplication
- 如果beanNameGenerator不为空,那么就把beanNameGenerator对象注入到context里去
- 回调所有的ApplicationContextInitializer方法
- 执行所有的SpringApplicationRunListener的contextPrepared方法
- 依次往spring容器中注入:ApplicationArguments,Banner
- 加载所有的源(source)到context中去
- 执行context的refresh方法,并且调用context的registerShutdownHook方法
- 回调,获取容器中所有的ApplicationRunner,CommandLineRunner接口,然后排序,依次调用
- 执行所有SpringApplicationRunListener的finished方法.
/**
* 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;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.started();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
listeners.environmentPrepared(environment);
if (isWebEnvironment(environment) && !this.webEnvironment) {
environment = convertToStandardEnvironment(environment);
}
return environment;
}
/**
* Strategy method used to create the {@link ApplicationContext}. By default this
* method will respect any explicitly set application context or application context
* class before falling back to a suitable default.
* @return the application context (not yet refreshed)
* @see #setApplicationContextClass(Class)
*/
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
contextClass = Class.forName(this.webEnvironment
? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}
/**
* Apply any relevant post processing the {@link ApplicationContext}. Subclasses can
* apply additional processing as required.
* @param context the application context
*/
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());
}
}
}
/**
* Apply any {@link ApplicationContextInitializer}s to the context before it is
* refreshed.
* @param context the configured ApplicationContext (not refreshed yet)
* @see ConfigurableApplicationContext#refresh()
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}