SpringBoot专题学习Part23:SpringBoot的启动原理 运行原理 自动配置原理及监听器的监听顺序

SpringBoot中有四个比较重要的事件回调机制

  • ApplicationContextInitializer
  • SpringApplicationRunListener
  • ApplicationRunner
  • CommandLineRunner

围绕着这四个接口 可了解SpringBoot的启动原理 运行原理 自动配置原理

启动时 调用了SpringApplication类的run()方法

public static void main(String[] args) {
    SpringApplication.run(SpringbootPrincipalApplication.class, args);
}

一、创建SpringApplication对象:

SpringBoot程序从启动类的main()方法开始 作为入口
创建SpringApplication对象 同时传入args参数 紧接着运行run()方法

在该方法中 给一些属性赋了默认值 然后调用initialize()方法

在该方法中 判断了主配置类的类型并保存 然后会判断当前应用是否为Web应用
然后会进入setInitializers()方法进行赋值 从类路径下找到/META-INF/spring.factories中找所有配置的ApplicationContextInitializer类 保存起来
之后还会从该路径下找所有的ApplicationListener 保存起来

然后从多个配置类中找到有main()方法的 即认为该类是主配置类
因而 运行SpringBoot应用的时候 允许传入多个配置类 允许传入数组格式
至此 SpringApplication对象创建完毕

二、run():

会创建一个空的ConfigurableApplicationContext
然后默认会从类路径下的/META-INF/spring.factories中获取SpringApplicationRunListener
获取完毕之后进入listener.starting() 遍历并启动所有listener的starting()方法
用ApplicationArguments封装args参数
进入准备环境方法 返回ConfigurableEnvironment对象
在准备环境方法中 创建了一个ConfigurableEnvironment类 并配置了环境
创建环境完成后 回调所有SpringApplicationRunListenerenvironmentPrepared()方法 表示环境准备完成了

之后 若不是Web环境 则转换为Web环境
然后 控制台中打印Spring图标
创建ApplicationContext 根据类型创建容器
之后用反射创建出IOC容器 再调用prepareContext()准备上下文环境 将environment保存到IOC容器中
再调用applyInitializer() 获取所有的Initializer 回调之前保存的所有ApplicationContextInitializerinitialize()方法
再回调所有的SpringApplicationRunListenercontextPrepare()方法 注册之前获取的参数和要打印的logo
当prepareContext运行完成之后 回调所有的SpringApplicationRunListenercontextLoaded()方法

调用refreshContext()方法 刷新容器 若为Web应用 还会创建嵌入式的Tomcat 总之 就是扫描 创建 加载所有的组件(配置类 组件 自动配置)
再调用afterRefresh()方法 里面调用callRunners()方法 从IOC容器中获取所有的ApplicationRunner(顺序是先回调)和CommandLineRunner(顺序是后回调)进行回调
最后所有SpringApplicationRunListener回调running()方法
至此 整个SpringBoot应用启动完成 启动完成之后 返回该启动的IOC容器


三、监听器测试

测试监听器的在程序运行过程中的监听时机
需要配置在META-INF/spring.factories的类:

扫描二维码关注公众号,回复: 10403833 查看本文章
  • ApplicationContextInitializer
  • SpringApplicationRunListener

只需要放在IOC容器中的类:

  • ApplicationRunner
  • CommandLineRunner

1、ApplicationContextInitializer

创建一个类 实现ApplicationContextInitializer接口 泛型为ConfigurableApplicationContext

public class HelloApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        System.out.println("HelloApplicationContextInitializer ===> initialize : "+configurableApplicationContext);
    }
}

2、SpringApplicationRunListener

创建一个类 实现SpringApplicationRunListener接口

public class HelloSpringApplicationRunListener implements SpringApplicationRunListener {

    // 需要一个有参构造器
    public HelloSpringApplicationRunListener(SpringApplication application,String[] args) {
    }

    @Override
    public void starting() {
        // 开始监听容器 环境准备
        System.out.println("HelloSpringApplicationRunListener ==> starting");
    }

    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        // 环境准备完毕
        System.out.println("HelloSpringApplicationRunListener ==> environmentPrepared : "+environment);
    }

    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        // IOC容器准备完毕
        System.out.println("HelloSpringApplicationRunListener ==> contextPrepared : "+context);
    }

    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        // 容器环境加载完成
        System.out.println("HelloSpringApplicationRunListener ==> contextLoaded : "+context);
    }

    @Override
    public void started(ConfigurableApplicationContext context) {
        // 容器被refreshed 应用启动
        System.out.println("HelloSpringApplicationRunListener ==> started : "+context);
    }

    @Override
    public void running(ConfigurableApplicationContext context) {
        // run方法完成 开始运行
        System.out.println("HelloSpringApplicationRunListener ==> running");
    }

    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        // 运行失败
        System.out.println("HelloSpringApplicationRunListener ==> failed : "+context);
    }
}

3、ApplicationRunner

创建一个类 实现ApplicationRunner接口

@Component
public class HelloApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("HelloApplicationRunner ==> run : "+args);
    }
}

4、CommandLineRunner

创建一个类 实现CommandLineRunner接口

@Component
public class HelloCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("HelloCommandLineRunner ==> run : "+Arrays.asList(args));
    }
}

要添加到容器中的类 只须在类上添加@Component注解即可

而要配置的类 须在resources包下创建META-INF包
里面创建一个spring.factories配置文件 用于配置路径:
( \ 代表换行 多个路径之间用逗号隔开)

# Initializers
org.springframework.context.ApplicationContextInitializer=\
net.zjitc.springboot.listener.HelloApplicationContextInitializer

# Listener
org.springframework.boot.SpringApplicationRunListener=\
net.zjitc.springboot.listener.HelloSpringApplicationRunListener

效果 - 监听顺序:
在这里插入图片描述


发布了174 篇原创文章 · 获赞 5 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/Piconjo/article/details/105132123
今日推荐