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类 并配置了环境
创建环境完成后 回调所有SpringApplicationRunListener的environmentPrepared()
方法 表示环境准备完成了
之后 若不是Web环境 则转换为Web环境
然后 控制台中打印Spring图标
创建ApplicationContext 根据类型创建容器
之后用反射创建出IOC容器 再调用prepareContext()
准备上下文环境 将environment保存到IOC容器中
再调用applyInitializer() 获取所有的Initializer 回调之前保存的所有ApplicationContextInitializer的initialize()
方法
再回调所有的SpringApplicationRunListener的contextPrepare()
方法 注册之前获取的参数和要打印的logo
当prepareContext运行完成之后 回调所有的SpringApplicationRunListener的contextLoaded()
方法
调用refreshContext()方法 刷新容器 若为Web应用 还会创建嵌入式的Tomcat 总之 就是扫描 创建 加载所有的组件(配置类 组件 自动配置)
再调用afterRefresh()方法 里面调用callRunners()方法 从IOC容器中获取所有的ApplicationRunner(顺序是先回调)和CommandLineRunner(顺序是后回调)进行回调
最后所有SpringApplicationRunListener回调running()
方法
至此 整个SpringBoot应用启动完成 启动完成之后 返回该启动的IOC容器
三、监听器测试
测试监听器的在程序运行过程中的监听时机
需要配置在META-INF/spring.factories的类:
- 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
效果 - 监听顺序: