SpringBoot是如何动起来的

点击上方“Java知音”,选择“置顶公众号”

技术文章第一时间送达!


作者:襄垣

juejin.im/post/5c6f730ce51d457f14363a53

(点击即可跳转阅读)

1. SpringBoot内容聚合

2. 面试题内容聚合

3. 设计模式内容聚合

4. Mybatis内容聚合

5. 多线程内容聚合

程序入口

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 声明

// 声明 ApplicationContextConfigurableApplicationContext 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 事件方法



SpringBoot相关内容

SpringBoot+Mybatis多模块(module)项目搭建教程

Springboot使用RedisTemplate优雅地操作redis

Springboot线程池的使用和扩展

SpringBoot 并发登录人数控制

Springboot如何优雅的解决ajax+自定义headers的跨域请求

优化你的springboot

Springboot总结,核心功能,优缺点

基于SpringBoot开发一个Restful服务,实现增删改查功能

深入SpringBoot核心注解原理

企业级SpringBoot与Dubbo的并用

Spring全家桶系列--[SpringBoot入门到跑路]

Spring全家桶系列--SpringBoot渐入佳境

Spring全家桶系列--SpringBoot之AOP详解

Spring全家桶--SpringBoot Rest API

Spring全家桶系列--SpringBoot与Mybatis结合

Spring全家桶系列--SpringBoot入门Redis

教你 Shiro 整合 SpringBoot,避开各种坑

教你 Shiro + SpringBoot 整合 JWT

SpringBoot 使用 Redis 缓存

SpringBoot启动流程解析

SpringBoot+MyBatis+MySQL读写分离(实例)

Springboot-Redis分布式锁

Springboot实战:集成Swagger2

SpringBoot整合RabbitMQ(一)快速入门

SpringBoot整合RabbitMQ(二)单机抢票系统

springboot整合websocket实现一对一消息推送和广播消息推送

SpringBoot常用注解大全


觉得不错?欢迎转发分享给更多人


640?


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值