首先加入依赖,
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.4.RELEASE</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
书写启动类,
@SpringBootApplication
public class Application {
public static void main(String[] args) {
//实例化SpringApplication对象,然后调用run方法
SpringApplication application = new SpringApplication(Application.class);
ConfigurableApplicationContext context = application.run(args);
//直接调用静态的run方法(内部转换成第一种调用方法)
//ConfigurableApplicationContext context =SpringApplication.run(Application.class, args);
}
}
我们知道启动类启动有二种方式第一种就是
实例化SpringApplication对象,然后调用run方法
SpringApplication application = new SpringApplication(Application.class);
ConfigurableApplicationContext context = application.run(args);
第二种就是
ConfigurableApplicationContext context =SpringApplication.run(Application.class, args);
然后我们进入第二种启动的run方法中,
再跟入run方法中
发现第二种方式就是第一种启动方式。
然后我们进入SpringApplication的构造函数中,分析一下SpringApplication的构造函数
/**
* 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);
}
initialize方法
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
//将启动源加入到一个set集合中
this.sources.addAll(Arrays.asList(sources));
}
//判断是否是web环境
this.webEnvironment = deduceWebEnvironment();
//加载所有classpath下面的META-INF/spring.factories的ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//加载所有classpath下面的META-INF/spring.factories的ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//推断main方法所在的类,一般是启动类
this.mainApplicationClass = deduceMainApplicationClass();
}
sources的定义,将启动源加入到一个set集合中
private final Set<Object> sources = new LinkedHashSet<Object>();
判断当前的spring项目是否是web环境,判断依据是当前项目中是否存在和加载Servlet和ConfigurableWebApplicationContext
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" };
以上是SpringApplication构造函数要做的事情。
加载所有classpath下面的META-INF/spring.factories的ApplicationContextInitializer调试结果(ApplicationContextInitializer接口是在spring容器刷新之前执行的一个回调函数)
加载所有classpath下面的META-INF/spring.factories的ApplicationListener(事件监听器)
run函数的源码分析
/**
* 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;
//设置java.awt.headless系统变量
configureHeadlessProperty();
//加载所有classpath下面的META-INF/spring.factories SpringApplicationRunListener(不同的时间点发送事件通知)
SpringApplicationRunListeners listeners = getRunListeners(args);
//执行所有SpringApplicationRunListener的started方法
listeners.starting();
try {
//根据启动args实例化ApplicationArguments对象
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//创建environment
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//打印Banner,执行到这一步的时候打印banner
Banner printedBanner = printBanner(environment);
//初始化applicationContext, 如果是web环境,则实例化AnnotationConfigEmbeddedWebApplicationContext对象,
//否则实例化AnnotationConfigApplicationContext对象
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
//进入prepareContext方法中
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//执行context的refresh方法,并且调用context的registerShutdownHook方法(这一步执行完成之后,spring容器就完全初始化好了)
refreshContext(context);
//回调,获取容器中所有的ApplicationRunner、CommandLineRunner接口,然后排序,依次调用
afterRefresh(context, applicationArguments);
//执行所有SpringApplicationRunListener的finished方法
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);
}
}
因为我这边是web环境,所以environment是webenvironment
配置environment,主要是把run方法的参数配置到environment
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
//Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
//配置environment,主要是把run方法的参数配置到environment
configureEnvironment(environment, applicationArguments.getSourceArgs());
//执行所有SpringApplicationRunListener的environmentPrepared方法
listeners.environmentPrepared(environment);
if (!this.webEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
return environment;
}
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
if (this.webEnvironment) {
return new StandardServletEnvironment();
}
return new StandardEnvironment();
}
初始化applicationContext, 如果是web环境,则实例化AnnotationConfigEmbeddedWebApplicationContext对象,否则实例化AnnotationConfigApplicationContext对象
/**
* 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);
}
进入prepareContext方法中
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
//如果beanNameGenerator不为空,就把beanNameGenerator对象注入到context里面去
postProcessApplicationContext(context);
//回调所有的ApplicationContextInitializer方法
applyInitializers(context);
//执行所有SpringApplicationRunListener的contextPrepared方法
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
//依次往spring容器中注入:ApplicationArguments,Banner
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
//加载所有的源到context里面去
load(context, sources.toArray(new Object[sources.size()]));
//执行所有SpringApplicationRunListener的contextLoaded方法
listeners.contextLoaded(context);
}
如果beanNameGenerator不为空,就把beanNameGenerator对象注入到context里面去
回调所有的ApplicationContextInitializer方法
执行所有SpringApplicationRunListener的contextPrepared方法
加载所有的源到context里面去
执行context的refresh方法,并且调用context的registerShutdownHook方法(这一步执行完成之后,spring容器就完全初始化好了),refresh完成之后容器就启动好了
回调,获取容器中所有的ApplicationRunner、CommandLineRunner接口,然后排序,依次调用
从上面的分析总结运行流程:
- 判断是否是web环境
- 加载所有classpath下面的META-INF/spring.factories ApplicationContextInitializer
- 加载所有classpath下面的META-INF/spring.factories ApplicationListener
- 推断main方法所在的类
- 开始执行run方法
- 设置java.awt.headless系统变量
- 加载所有classpath下面的META-INF/spring.factories SpringApplicationRunListener(不同的时间点发送事件通知)
- 执行所有SpringApplicationRunListener的started方法
- 根据启动args实例化ApplicationArguments对象
- 创建environment
- 配置environment,主要是把run方法的参数配置到environment
- 执行所有SpringApplicationRunListener的environmentPrepared方法
- 如果不是web环境,但是是web的environment,则把这个web的environment转换成标准的environment
- 打印Banner
- 初始化applicationContext, 如果是web环境,则实例化AnnotationConfigEmbeddedWebApplicationContext对象,否则实例化AnnotationConfigApplicationContext对象
- 如果beanNameGenerator不为空,就把beanNameGenerator对象注入到context里面去
- 回调所有的ApplicationContextInitializer方法
- 执行所有SpringApplicationRunListener的contextPrepared方法
- 依次往spring容器中注入:ApplicationArguments,Banner
- 加载所有的源到context里面去
- 执行所有SpringApplicationRunListener的contextLoaded方法
- 执行context的refresh方法,并且调用context的registerShutdownHook方法(这一步执行完成之后,spring容器就完全初始化好了)
- 回调,获取容器中所有的ApplicationRunner、CommandLineRunner接口,然后排序,依次调用
- 执行所有SpringApplicationRunListener的finished方法