欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

厉害了!SpringBoot是如何动起来的!

程序员文章站 2022-06-11 16:42:30
程序入口 SpringApplication.run(BeautyApplication.class, args); 执行此方法来加载整个SpringBoot的环境。 1. 从哪儿开始? SpringApplication.java /** * Run the Spring application, ......

程序入口

springapplication.run(beautyapplication.class, args);

 

执行此方法来加载整个springboot的环境。

1. 从哪儿开始?

springapplication.java

  /**
     * run the spring application, creating and refreshing a new
     * {@link applicationcontext}.
     * @param args the application arguments (usually passed from a java main method)
     * @return a running {@link applicationcontext}
     */
    public configurableapplicationcontext run(string... args) {
        //...
  }

 

调用springapplication.java 中的 run 方法,目的是加载spring application,同时返回 applicationcontext。

2. 执行了什么?

2.1 计时

记录整个spring application的加载时间!

stopwatch stopwatch = new stopwatch();
stopwatch.start();
// ...
stopwatch.stop();
if (this.logstartupinfo) {
    new startupinfologger(this.mainapplicationclass)
            .logstarted(getapplicationlog(), stopwatch);
}

 

2.2 声明

// 声明 applicationcontext
configurableapplicationcontext context = null;
// 声明 一个异常报告集合
collection<springbootexceptionreporter> exceptionreporters = new arraylist<>();

 

2.3 指定程序运行模式

指定 java.awt.headless,默认是true 一般是在程序开始激活headless模式,告诉程序,现在你要工作在headless mode下,就不要指望硬件帮忙了,你得自力更生,依靠系统的计算能力模拟出这些特性来。

private void configureheadlessproperty() {
    system.setproperty(system_property_java_awt_headless, system.getproperty(
            system_property_java_awt_headless, boolean.tostring(this.headless)));
}

 

2.4 配置监听并发布应用启动事件

springapplicationrunlistener 负责加载 applicationlistener事件。

springapplicationrunlisteners listeners = getrunlisteners(args);
// 开始
listeners.starting();
// 处理所有 property sources 配置和 profiles 配置,准备环境,分为标准 servlet 环境和标准环境
configurableenvironment environment = prepareenvironment(listeners,applicationarguments);
// 准备应用上下文
preparecontext(context, environment, listeners, applicationarguments,printedbanner);
// 完成
listeners.started(context);
// 异常
handlerunfailure(context, ex, exceptionreporters, listeners);
// 执行
listeners.running(context);

 

getrunlisteners 中根据 type = springapplicationrunlistener.class 去拿到了所有的 listener 并根据优先级排序。

对应的就是 meta-inf/spring.factories 文件中的 org.springframework.boot.springapplicationrunlistener=org.springframework.boot.context.event.eventpublishingrunlistener

private <t> collection<t> getspringfactoriesinstances(class<t> type,
            class<?>[] parametertypes, object... args) {
        classloader classloader = thread.currentthread().getcontextclassloader();
        // use names and ensure unique to protect against duplicates
        set<string> names = new linkedhashset<>(
                springfactoriesloader.loadfactorynames(type, classloader));
        list<t> instances = createspringfactoriesinstances(type, parametertypes,
                classloader, args, names);
        annotationawareordercomparator.sort(instances);
        return instances;
    }

 

在 applicationlistener 中 , 可以针对任何一个阶段插入处理代码。

public interface springapplicationrunlistener {

    /**
     * called immediately when the run method has first started. can be used for very
     * early initialization.
     */
    void starting();

    /**
     * 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);

    /**
     * the context has been refreshed and the application has started but
     * {@link commandlinerunner commandlinerunners} and {@link applicationrunner
     * applicationrunners} have not been called.
     * @param context the application context.
     * @since 2.0.0
     */
    void started(configurableapplicationcontext context);

    /**
     * called immediately before the run method finishes, when the application context has
     * been refreshed and all {@link commandlinerunner commandlinerunners} and
     * {@link applicationrunner applicationrunners} have been called.
     * @param context the application context.
     * @since 2.0.0
     */
    void running(configurableapplicationcontext context);

    /**
     * called when a failure occurs when running the application.
     * @param context the application context or {@code null} if a failure occurred before
     * the context was created
     * @param exception the failure
     * @since 2.0.0
     */
    void failed(configurableapplicationcontext context, throwable exception);

}

 

3. 每个阶段执行的内容

3.1 listeners.starting();

在加载spring application之前执行,所有资源和环境未被加载。

3.2 prepareenvironment(listeners, applicationarguments);

创建 configurableenvironment;将配置的环境绑定到spring application中;

    private configurableenvironment prepareenvironment(
            springapplicationrunlisteners listeners,
            applicationarguments applicationarguments) {
        // create and configure the environment
        configurableenvironment environment = getorcreateenvironment();
        configureenvironment(environment, applicationarguments.getsourceargs());
        listeners.environmentprepared(environment);
        bindtospringapplication(environment);
        if (this.webapplicationtype == webapplicationtype.none) {
            environment = new environmentconverter(getclassloader())
                    .converttostandardenvironmentifnecessary(environment);
        }
        configurationpropertysources.attach(environment);
        return environment;
    }

 

3.3 preparecontext

配置忽略的bean;

 private void configureignorebeaninfo(configurableenvironment environment) {
        if (system.getproperty(
                cachedintrospectionresults.ignore_beaninfo_property_name) == null) {
            boolean ignore = environment.getproperty("spring.beaninfo.ignore",
                    boolean.class, boolean.true);
            system.setproperty(cachedintrospectionresults.ignore_beaninfo_property_name,
                    ignore.tostring());
        }
    }

 

打印日志-加载的资源

banner printedbanner = printbanner(environment);

 

根据不同的webapplicationtype创建context

context = createapplicationcontext();

 

3.4 refreshcontext

支持定制刷新

 /**
     * register a shutdown hook with the jvm runtime, closing this context
     * on jvm shutdown unless it has already been closed at that time.
     * <p>this method can be called multiple times. only one shutdown hook
     * (at max) will be registered for each context instance.
     * @see java.lang.runtime#addshutdownhook
     * @see #close()
     */
    void registershutdownhook();

 

3.5 afterrefresh

刷新后的实现方法暂未实现

 /**
     * called after the context has been refreshed.
     * @param context the application context
     * @param args the application arguments
     */
    protected void afterrefresh(configurableapplicationcontext context,
            applicationarguments args) {
    }

 

3.6 listeners.started(context);

到此为止, spring application的环境和资源都加载完毕了;发布应用上下文启动完成事件;执行所有 runner 运行器 - 执行所有 applicationrunner 和 commandlinerunner 这两种运行器。

// 启动
callrunners(context, applicationarguments);

 

3.7 listeners.running(context);

触发所有 springapplicationrunlistener 监听器的 running 事件方法

 

(完)

本人免费整理了java高级资料,涵盖了java、redis、mongodb、mysql、zookeeper、spring cloud、dubbo高并发分布式等教程,一共30g,需要自己领取。
传送门:https://mp.weixin.qq.com/s/osb-bol6w-zltstttkqmpq