SpringBoot高级-监听原理
Java监听机制中定义了以下几个角色:
- 事件:Event,继承java.util.EventObject类的对象
- 事件源:Source,任意对象Object;
- 监听器:Listener,实现java.util.EventListener接口的对象
SpringBoot的监听机制就是对Java的监听机制的封装。
SpringBoot监听机制
SpringBoot在项目启动时,会对几个监听器进行回调,我们可以实现这些监听器接口,在项目启动时完成一些操作。
SpringBoot中可以实现的监听器接口有四个:
- ApplicationContextInitializer
- SpringApplicationRunListener
- CommandLineRunner
- ApplicationRunner
其中第三个和第四个功能类似,只是方法的参数类型不同。
示例
1、新建一个工程,分别实现上述四个监听器接口(ApplicationContextInitializer:虽然名字上没有监听器字眼,但是实现机制也是监听器的原理)
代码如下:
①实现 ApplicationContextInitializer 接口
@Component
public class MyApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("ApplicationContextInitializer...");
}
}
②实现 SpringApplicationRunListener 接口
@Component
public class MySpringApplicationRunListener implements SpringApplicationRunListener {
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
System.out.println("starting...项目启动中");
}
@Override
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
System.out.println("environmentPrepared...环境对象开始准备");
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("contextPrepared...上下文对象开始准备");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("contextLoaded...上下文对象开始加载");
}
@Override
public void started(ConfigurableApplicationContext context) {
System.out.println("started...上下文对象加载完成");
}
@Override
public void running(ConfigurableApplicationContext context) {
System.out.println("running...项目启动完成,开始运行");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("failed...项目启动失败");
}
}
③实现 CommandLineRunner 接口
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CommandLineRunner#run");
}
}
④实现 ApplicationRunner 接口
@Component
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner#run");
}
}
2、启动项目,控制台输出日志
可以看到只有MyCommandLineRunner 和 MyApplicationRunner 监听器启动并生效了,这两种监听器功能类似,实际使用时用其中一种即可
3、使MySpringApplicationRunListener 监听器生效
在resources目录下新建一个META-INF目录并新建一个spring.factories文件
文件内容为注册 MySpringApplicationRunListener 监听器
org.springframework.context.ApplicationContextInitializer=\
com.winson.springbootlistener.listener.MyApplicationContextInitializer
再次启动项目,控制台日志如下,MySpringApplicationRunListener 生效,在banner打印之后,在spring的IOC容器启动前作用,实际应用时可以用作资源检测。
4、使 MySpringApplicationRunListener 监听器生效
我们在spring.factories文件将 MySpringApplicationRunListener 监听器也注册
org.springframework.context.ApplicationContextInitializer=\
com.winson.springbootlistener.listener.MyApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=\
com.winson.springbootlistener.listener.MySpringApplicationRunListener
启动程序,报异常:java.lang.NoSuchMethodException: com.winson.springbootlistener.listener.MySpringApplicationRunListener.
我们找到 SpringApplicationRunListener 接口 的另一个实现类 EventPublishingRunListener 就有init方法,仿照该init方法,在我们自定义的实现类中也写一个init方法(参数也一致)
添加初始化方法(带参构造方法)后如下(类上的@Component注解删除,否则报错,无法注入SpringApplication):
public class MySpringApplicationRunListener implements SpringApplicationRunListener {
public MySpringApplicationRunListener(SpringApplication application, String[] args) {
}
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
System.out.println("starting...项目启动中");
}
@Override
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
System.out.println("environmentPrepared...环境对象开始准备");
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("contextPrepared...上下文对象开始准备");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("contextLoaded...上下文对象开始加载");
}
@Override
public void started(ConfigurableApplicationContext context) {
System.out.println("started...上下文对象加载完成");
}
@Override
public void running(ConfigurableApplicationContext context) {
System.out.println("running...项目启动完成,开始运行");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("failed...项目启动失败");
}
}
再次启动程序,控制台日志,发现 MySpringApplicationRunListener 监听器生效了,该监听器几乎作用在整个程序启动的生命周期里:
小结:实际工作中,我们就可以利用监听器,在程序启动的不同阶段设置具体的业务功能
下面简介SpringBoot中默认的监听器
在依赖中,我们发现SpringBoot已经定义了各个阶段的监听器,打开具体一个查看,其它的大家可以再逐一查看。