spring boot到底干了啥(一)

不想你离开。 提交于 2020-08-15 23:22:21

前言

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!