SpringApplication 在各种赋值都完成, 初始化部分已完成,下一步是根据初始化的各种配置,对应用进行启动,包括bean的加载,配置文件的读入等等, 调用的方法为:
springApplication.run(args);
源码(版本为Spring-boot-1.3.0.M5)如下:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.started();
try {
context = doRun(listeners, args);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(
getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
try {
listeners.finished(context, ex);
this.log.error("Application startup failed", ex);
}
finally {
if (context != null) {
context.close();
}
}
ReflectionUtils.rethrowRuntimeException(ex);
return context;
}
}
1. StopWatch 监控
用来记录任务的启动 结束时间,是一个非线程的安全的,如果自己使用要考虑多线程的情况.
2. 配置Headless模式, configureHeadlessProperty
private void configureHeadlessProperty() {
System.setProperty(
SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
Boolean.toString(this.headless)));
}
用来设置java.awt.headless 属性是true 还是false, java.awt.headless是J2SE的一种模式用于在缺少显示屏、键盘或者鼠标时的系统配置,很多监控工具如jconsole 需要将该值设置为true.
3. SpringApplicationRunListener 对ApplicationListener事件处理
在初始化的时候 我们加载了一批 ApplicationListener,包括springboot自启动的 ,也可以有用户定义ApplicationListener,SpringApplicationRunListener就负责来加载ApplicationListener中的业务.
/**
* Called immediately when the run method has first started. Can be used for very
* early initialization.
*/
void started();
/**
* Called once the environment has been prepared, but before the
* {@link ApplicationContext} has been created.
* @param environment the environment
*/
void environmentPrepared(ConfigurableEnvironment environment);
/**
* Called once the {@link ApplicationContext} has been created and prepared, but
* before sources have been loaded.
* @param context the application context
*/
void contextPrepared(ConfigurableApplicationContext context);
/**
* Called once the application context has been loaded but before it has been
* refreshed.
* @param context the application context
*/
void contextLoaded(ConfigurableApplicationContext context);
/**
* Called immediately before the run method finishes.
* @param context the application context
* @param exception any run exception or null if run completed successfully.
*/
void finished(ConfigurableApplicationContext context, Throwable exception);
ApplicationListener可以实现四中event类型, 分别在不同的时候加载, ApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent,ApplicationFailedEvent , ApplicationStartedEvent.
在run的方法中分别使用在:
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.started();
listeners.environmentPrepared(environment);
listeners.contextPrepared(context);
listeners.finished(context, null);
4. doRun 方法实现
private ConfigurableApplicationContext doRun(SpringApplicationRunListeners listeners,
String... args) {
ConfigurableApplicationContext context;
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, args);
listeners.environmentPrepared(environment);
if (this.showBanner) {
printBanner(environment);
}
// Create, load, refresh and run the ApplicationContext
context = createApplicationContext();
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
}
// Add boot specific singleton beans
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
// Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context);
// Refresh the context
refresh(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
return context;
}```
#####a. 创建和配置环境相关
i. 创建 environment
首先根据初始化的配置创建environment的类型, 后面或者property 和profile都是通过这个类来获取的,然后configureEnvironment 就是用来Property和Profiled的.
ii. 启动说监听器的environmentPrepared方法,会调用所有监听器中监听ApplicationEnvironmentPreparedEvent的方法,具体逻辑在上一步中已经描述了.
iii. printBanner
打印启动的banner,工业化的项目中可以对此进行定制,使用Banner类即可.
#####b. 创建 加载 刷新 运行ApplicationContext
i.创建context
```java
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);
}
根据是否是webEnvironment 创建不同的context,是创建的是AnnotationConfigEmbedded,WebApplicationContext, 不是创建的默认的 AnnotationConfig, ApplicationContext.
ii.注册关闭的钩子,主要实现当JVM关闭时候,做一些关闭处理,如销毁bean,生命周期关闭等, 实现方式是
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
JVM关闭时会自动调用.
iii. initializer 初始化 日志启动等其他操作.
c. 配置spring boot特有的单例bean 如commandline相关
d.加载资源,就是在初始化过程中source包含的类
e.context 重新刷新
这个主要都走spring 框架的AbstractApplicationContext#refresh,是对context中的各种资源进行加载, 由于不是boot特有,这里不仔细描述
f.监听器实现所有finished操作
主要的实现ApplicationReadyEvent 或者 ApplicationFailedEvent.
至此,springboot启动过程分析完成了.
5. 后记
本身主要研究分析了boot本身的代码的情况,并没有对spring的代码 和 每个监听器功能进行深入分析后面可开专门文章对此进行补充 ,方便不熟悉spring的同学理解.