SpringBoot(1) 启动

403 阅读2分钟

说明:本系列的spring boot版本为2.1.1.RELEASE。

启动

引入和启动一个SpringBoot的项目非常简单,maven导入jar包后,一个最简单的SpringBoot项目只需一个注解和一行代码。

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(DemoApplication.class);
        springApplication.run(args);
    }
}

SpringApplication有很多属性,我们可以在run之前用set方法赋予成员变量的属性,也可以用构建者模式赋予变量属性,这两种方式本质上没有区别。

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        new SpringApplicationBuilder(DemoApplication.class)
                .build()
                .run(args);
    }
}

实例化

SpringApplication->SpringApplication():
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 设置servlet环境
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 成员变量initializers设置ApplicationContextInitializer
    setInitializers((Collection) getSpringFactoriesInstances(
            ApplicationContextInitializer.class));
    // 成员变量listeners添加监听器
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // 将main方法所在类设置为主应用类
    this.mainApplicationClass = deduceMainApplicationClass();

getSpringFactoriesInstances()方法,根据传过来的Class调用SpringFactoriesLoader.loadFactoryNames()得到配置文件spring.factories中的全限定名,然后利用反射实例化,最终返回一个List集合。

监听器与Tomcat中的监听器作用如出一辙,当生命周期变化时,监听器将会处理对应的事件。

前言:

运行监听器类SpringApplicationRunListeners

实例化完成后,调用run()方法

SpringApplication->run():
    // getRunListeners(args)得到配置文件中指定
    // org.springframework.boot.SpringApplicationRunListener的属性
    SpringApplicationRunListeners listeners = getRunListeners(args);
    // 注意run方法下所有的listeners都是运行监听器
    listeners.starting();

getRunListeners(args)spring.factories中得到运行监听器,在SpringBoot中只有EventPublishingRunListener,顾名思义与事件的发布有关,最后封装成SpringApplicationRunListeners类返回。

SpringApplicationRunListeners->starting():
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.starting();
    }
EventPublishingRunListener->starting():
    this.initialMulticaster.multicastEvent(
            new ApplicationStartingEvent(this.application, this.args));
SimpleApplicationEventMulticaster->multicastEvent():
    multicastEvent(event, resolveDefaultEventType(event));

注意到这里的事件类型为应用启动事件ApplicationStartingEvent,它是抽象类SpringApplicationEvent的子类,实际上SpringBoot的所有事件类都是SpringApplicationEvent的子类

SimpleApplicationEventMulticaster->multicastEvent():
    // 先遍历所有监听器,得到支持ApplicationStartingEvent事件类型及SpringApplication类的监听器
    // 再遍历监听器,处理对应的事件
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        invokeListener(listener, event);
    }
SimpleApplicationEventMulticaster->invokeListener():
    doInvokeListener(listener, event);
SimpleApplicationEventMulticaster->doInvokeListener():
    listener.onApplicationEvent(event);

本例中SpringBoot的监听器如下图所示

image.png

监听器是否支持事件类型最终由supportsEvent()决定,最终决策如下流程图

未命名文件 (6).jpg

监听器类都需要实现ApplicationListener接口,它的泛型是ApplicationEvent或其子类,图中的泛型类即为此。

image.png 自定义监听器类

附录:banner

启动方法中注意到有这样的一行代码Banner printedBanner = printBanner(environment);(前面的过程暂且先不管)。

SpringApplication->printBanner():
    // 默认在控制台打印
    return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
SpringApplicationBannerPrinter->print():
    Banner banner = getBanner(environment);
    banner.printBanner(environment, sourceClass, out);
SpringApplicationBannerPrinter->getBanner():
    banners.addIfNotNull(getImageBanner(environment));
    banners.addIfNotNull(getTextBanner(environment));

getImageBanner()获取配置文件中spring.banner.image.location设置的路径,如果没有的话,尝试依次读取resources目录下的bannner.gif, bannner.jpg, bannner.png,设置了任意一文件就返回;getTextBanner()获取配置文件中spring.banner.location设置的路径,如果没有的话,尝试读取resources目录下的bannner.txt。这两个方法哪个有就打印哪个,都没有的话打印默认banner(SpringBoot的logo)。

还可以给bannner设置字体,颜色,版本号等属性,具体可以研究源代码(位于ResourceBanner->printBanner()),下图是设置为佛祖保佑打印出来的效果。

image.png