核心原理
事件和监听器
生命周期监听器
自定义SpringApplicationRunListener来监听事件;
- 编写SpringApplicationRunListener 实现类
- 在 META-INF/spring.factories 中配置 org.springframework.boot.SpringApplicationRunListener=自己的Listener,还可以指定一个有参构造器,接受两个参数(SpringApplication application, String[] args)
执行顺序
Listener先要从 META-INF/spring.factories 读到
- 引导: 利用 BootstrapContext(启动上下文) 引导整个项目启动
- starting:
- 应用开始,SpringApplication的run方法一调用,只要有了 BootstrapContext 就执行
- 触发ApplicationStartingEvent事件
- environmentPrepared:
- 环境准备好(把启动参数等绑定到环境变量中),但是ioc还没有创建;【调一次】
- 触发ApplicationEnvironmentPreparedEvent事件
- 启动:
- contextPrepared:
- ioc容器创建并准备好,但是sources(主配置类)没加载。并关闭引导上下文;组件都没创建 【调一次】
- 触发ApplicationContextInitializedEvent事件
- contextLoaded:
- ioc容器加载。主配置类加载进去了。但是ioc容器还没刷新(我们的bean没创建)。
- 触发ApplicationPreparedEvent事件
- started:
- ioc容器刷新了(所有bean造好了),但是 runner 没调用。
- 触发AvailabilityChangeEvent事件(存活探针)
- ready:
- ioc容器刷新了(所有bean造好了),所有 runner 调用完了。
- 触发AvailabilityChangeEvent事件事件(就绪探针)
- 运行
- 以前步骤都正确执行,代表容器running。
- 启动失败(以上步骤仍一失败)
- 若应用启动失败则调用该方法
- 触发ApplicationFailedEvent事件
生命周期监听器
package com.atli.springbootweb;
public class MyAppListener implements SpringApplicationRunListener {
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
System.out.println("应用启动");
}
@Override
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
System.out.println("环境准备就绪");
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("ioc容器创建成功");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("ioc容器主配置类加载成功(ioc容器加载完成)");
}
@Override
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
System.out.println("ioc容器中所有bean创建成功(启动完成,还未初始化)");
}
@Override
public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
System.out.println("ioc容器初始化完成(bean建立完成且runner调用完成)");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("应用启动失败");
}
}
声明周期监听器配置文件
# resources/META-INFO/spring.factories
org.springframework.boot.SpringApplicationRunListener=com.atli.springbootweb.MyAppListener
事件触发时机
回调监听器
- BootstrapRegistryInitializer:
- 感知特定阶段:感知引导初始化
- 创建引导上下文bootstrapContext的时候触发。
- 场景:进行密钥校对授权。
- 通过配置META-INF/spring.factories使用
- 或者在main中配置application.addBootstrapRegistryInitializer();使用
- ApplicationContextInitializer:
- 感知特定阶段: 感知ioc容器初始化
- META-INF/spring.factories
- application.addInitializers();
- ApplicationListener:
- 感知全阶段:基于事件机制,感知事件。 一旦到了哪个阶段可以做别的事
- @Bean或@EventListener: 事件驱动
- SpringApplication.addListeners(…)或 SpringApplicationBuilder.listeners(…)
- META-INF/spring.factories
- SpringApplicationRunListener:
- 感知全阶段生命周期 + 各种阶段都能自定义操作; 功能更完善。
- 通过配置META-INF/spring.factories使用
- ApplicationRunner:
- 感知特定阶段:感知应用就绪Ready。卡死应用,就不会就绪
- 通过@Bean标记使用
- CommandLineRunner:
- 感知特定阶段:感知应用就绪Ready。卡死应用,就不会就绪
- 通过@Bean标记使用
完整的九大事件触发顺序
- ApplicationStartingEvent:
- 应用启动但未做任何事情, 除过注册listeners and initializers.
- ApplicationEnvironmentPreparedEvent:
- Environment 准备好,但context 未创建.
- ApplicationContextInitializedEvent:
- ApplicationContext 准备好,ApplicationContextInitializers 调用,但是任何bean未加载
- ApplicationPreparedEvent:
- 容器刷新之前,bean定义信息加载
- ApplicationStartedEvent:
- 容器刷新完成, runner未调用
=以下就开始插入了探针机制====
- AvailabilityChangeEvent:
- LivenessState.CORRECT应用存活; 存活探针
- ApplicationReadyEvent:
- 任何runner被调用
- AvailabilityChangeEvent:
- ReadinessState.ACCEPTING_TRAFFIC就绪探针,可以接请求
- ApplicationFailedEvent :
- 启动出错
事件驱动开发
- 使用该技术,利用应用启动过程中对生命周期事件和应用运行中事件的感知可以实现订阅-发布模式
- 使用该模式可以实现对修改关闭,对扩展开放的设计原则
- 创建一个事件类继承ApplicationEvent类,并在构造器中调用super的构造器方法,传入该事件信息
- 创建一个事件发布类,实现ApplicationEventPublisherAware接口,实现该接口的setApplicationEventPublisher方法,创建一个成员变量来接收实现方法的形参。编写一个发布事件的方法,调用applicaitonEventPublisher的publishEvent方法
事件发布者
@Service
public class EventPublisher implements ApplicationEventPublisherAware {
/**
* 底层发送事件用的组件,SpringBoot会通过ApplicationEventPublisherAware接口自动注入给我们
* 事件是广播出去的。所有监听这个事件的监听器都可以收到
*/
ApplicationEventPublisher applicationEventPublisher;
/**
* 会被自动调用,把真正发事件的底层组组件给我们注入进来
* @param applicationEventPublisher event publisher to be used by this object
*/
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
/**
* 利用多态实现可以发送所有类型的事件
* @param event
*/
public void sendEvent(ApplicationEvent event) {
//调用底层API发送事件
applicationEventPublisher.publishEvent(event);
}
}
事件订阅者
@Service
public class CouponService {
// 设置事件的优先级
@Order(1)
@EventListener
public void onEvent(LoginSuccessEvent loginSuccessEvent){
System.out.println("===== CouponService ====感知到事件"+loginSuccessEvent);
UserEntity source = (UserEntity) loginSuccessEvent.getSource();
sendCoupon(source.getUsername());
}
public void sendCoupon(String username){
System.out.println(username + " 随机得到了一张优惠券");
}
}
自定义事件
public class LoginSuccessEvent extends ApplicationEvent{
/**
* @param source 代表登录成功的对象,自己写一个类,比如包括用户名之类的
*/
public LoginSuccessEvent(UserEntity source){
super(source);
}
}
事件触发者
@RestController
public class UserController{
@Autowired
EventPublisher enventPublisher
//发送事件
enventPublisher.sendEvent(new LoginSuccessEvent(new UserEntity("1","li","18")))
}