前言
对于服务端开发来说,新项目大多数都会基于spring boot进行开发。 而是用spring boot的项目一般都会有这么一行代码
SpringApplication.run(TestApplication.class, args);
这是Spring boot框架载入的地方。心血来潮,想看看它到底做了些什么。
new SpringApplication(primarySources))
run 方法会首先创建一个 SpringApplicaition对象,而primarySources 就是我们run方法的第一个参数,比如TestApplication.class
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.isCustomEnvironment = false;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}
造这个构造方法里主要有这么几个部分
WebApplicationType.deduceFromClasspath
这个方法主要用来获取 当前应用的类型,如果我们引入了 spring-webmvc 那么就会返回 servlet,如果我们使用WebFlux做反应式框架时,就会返回REACTIVE,这我们后面再说。
getSpringFactoriesInstances(Class classz)
该方法是找到 META-INF/spring.factories 文件下,所有 classz类型的类,然后在加载到内存中,并且调用默认构造函数,生成一个实例。
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
所以我们就能知道,这行代码的含义就是实例化 META-INF/spring.factories 文件中 所有 ApplicationContextInitializer 类型的类。至于这个类型的类有什么作用,我们后面会看到。 以上,所有springboot中的 ApplicationContextInitializer 实例都会被创建。 假设我们想添加自己的ApplicationContextInitializer可以这样写。
@SpringBootApplication
public class MySpringBootApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MySpringBootApplication.class);
application.addInitializers(new MyApplicationContextInitializer());
application.run(args);
}
}
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
同上
deduceMainApplicationClass()
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = (new RuntimeException()).getStackTrace();
StackTraceElement[] var2 = stackTrace;
int var3 = stackTrace.length;
for(int var4 = 0; var4 < var3; ++var4) {
StackTraceElement stackTraceElement = var2[var4];
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
} catch (ClassNotFoundException var6) {
;
}
return null;
}
实际上就是从当前调用栈中找到包含main方法的类,并且将该类的类型返回。
run()
public ConfigurableApplicationContext run(String... args) {
//<1>
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//<2>
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
// <3>
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//<4>
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
//<5>
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
<1> StopWatch
目前的理解是一个计时器,主要用于记录spring boot的启动时长。
<2> configureHeadlessProperty
用于设置系统的 headless模式。简单来说,该模式告诉系统,目前缺少显示器,键盘鼠标。(java 部分类运行会依赖显示器等设备,这里就是告诉他们,这些不可依赖。)
<3> SpringApplicationRunListeners
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
getSpringFactoriesInstances 已经是老面孔了,获取所有META-INF/spring.factories 文件中定义的 SpringApplicationRunListener 类型的类。然后将其存放入SpringApplicationRunListeners中。
最后starting方法就是调用 SpringApplicationRunListeners中 所有 SpringApplicationRunListener 对象的starting方法。
在没有自定义的情况下,只有一个SpringApplicationRunListener会被调用 ——EventPublishingRunListener。
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
Iterator var3 = application.getListeners().iterator();
while(var3.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var3.next();
//这里实际上就是所有ApplicationListener类型的实例,上面有介绍
this.initialMulticaster.addApplicationListener(listener);
}
}
……
public void starting() {
//创建一个 ApplicationStartingEvent 事件(表示应用启动),然后广播这个事件看看谁会监听。
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
最终监听者有如下几个
LoggingApplicationListener : 配置LoggingSystem。 BackgroundPreinitializer: 在后台启一个线程,用来做一些耗时的初始化任务。 DelegatingApplication : 监听到事件后转发给环境变量context.listener.classes指定的那些事件监听器. LiquibaseServiceLocatorApplicationListener : Liquibase 一个数据库迁移的开源工具。该监听器对这个迁移工具做了特殊支持。
来源:oschina
链接:https://my.oschina.net/zzxzzg/blog/4298626