springboot到底干了啥(一)

编程

前言

对于服务端开发来说,新项目大多数都会基于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 一个数据库迁移的开源工具。该监听器对这个迁移工具做了特殊支持。

以上是 springboot到底干了啥(一) 的全部内容, 来源链接: utcz.com/z/517025.html

回到顶部