1、是什么?
SpringBoot事件机制是指SpringBoot中的开发人员可以通过编写自定义事件来对应用程序进行事件处理。我们可以创建自己的事件类,并在应用程序中注册这些事件,当事件被触发时,可以对其进行处理。在SpringBoot中,事件可以是任意类型的,可以是基于Spring的事件,也可以是自定义的事件。事件处理可以是在应用程序中特定的方法中进行,也可以是通过Spring提供的事件处理API进行处理。
主要有三大对象:
- 1、事件源 :具体的事件内容
- 2、事件发布者 :发布事件
- 3、事件监听者 :监听事件
9大事件触发顺序&时机
1、ApplicationStartingEvent:应用启动但未做任何事情, 除过注册listeners and initializers.
2、ApplicationEnvironmentPreparedEvent: Environment 准备好,但context 未创建.
3、ApplicationContextInitializedEvent: ApplicationContext 准备好,ApplicationContextInitializers 调用,但是任何bean未加载
4、ApplicationPreparedEvent: 容器刷新之前,bean定义信息加载
5、ApplicationStartedEvent: 容器刷新完成, runner未调用
=以下就开始插入了探针机制====
6、AvailabilityChangeEvent: LivenessState.CORRECT应用存活; 存活探针
7、ApplicationReadyEvent: 任何runner被调用
8、AvailabilityChangeEvent:ReadinessState.ACCEPTING_TRAFFIC就绪探针,可以接请求
9、ApplicationFailedEvent :启动出错
2、怎么玩?
这样把,我们先模拟一个场景:现在有一个用户打卡的需求,用户登录进行签到打卡,打卡会奖励一些积分;当连续打卡次数到了7次我们就送一张优惠券。当然除了前面的操作我们还需要记录一下用户的登录日志
明确一下:
- 1、加积分
- 2、送优惠券
- 3、记录登录日志
常规写法如下:
@Autowired
private AccountService accountService;
@Autowired
private CouponService couponService;
@Autowired
private SystemService systemService;
@GetMapping("/login")
public String login(@RequestParam String username,
@RequestParam String password) {
// 伪代码
// login......
// 加积分
accountService.addAccountScore(username);
// 送优惠券
couponService.addCoupon(username);
// 记录登录日志
systemService.addLoginLog(username);
// 等等....
return "success";
}
问题:上面的代码实现功能是没问题的,但是如果我还需要做其他的操作岂不是每次都得修改代码加功能了...,这不是我们想要的,也不符合【开闭原则】;下面我们就用时间解耦上面的代码
(1) 定义一个事件发布器
package com.ly.event;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
/**
* 事件发布器
*
* @author ly (个人博客:https://www.cnblogs.com/ybbit)
* @date 2023-06-26 20:06
* @tags 喜欢就去努力的争取
*/
@Service
public class EventPublisher implements ApplicationEventPublisherAware {
ApplicationEventPublisher applicationEventPublisher;
/**
* 发送所有事件
*
* @param event
*/
public void sendEvent(ApplicationEvent event) {
// 真正的发送事件
this.applicationEventPublisher.publishEvent(event);
}
/**
* 会被自动调用,把真正发事件的底层组件给我们注入进来
*
* @param applicationEventPublisher
*/
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
}
(2) 定义一个事件
package com.ly.event;
import com.ly.entity.UserEventEntity;
import org.springframework.context.ApplicationEvent;
/**
* 事件
*
* @author ly (个人博客:https://www.cnblogs.com/ybbit)
* @date 2023-06-26 20:06
* @tags 喜欢就去努力的争取
*/
public class LoginSuccessEvent extends ApplicationEvent {
public LoginSuccessEvent(UserEventEntity source) {
super(source);
}
}
(3) 定义一个事件对象
package com.ly.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author ly (个人博客:https://www.cnblogs.com/ybbit)
* @date 2023-06-26 20:05
* @tags 喜欢就去努力的争取
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserEventEntity {
private String username;
private String password;
}
(4) 编写相关逻辑(伪代码)
AccountService
package com.ly.service;
import com.ly.entity.UserEventEntity;
import com.ly.event.LoginSuccessEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Service;
/**
* 记录积分
*
* @author ly (个人博客:https://www.cnblogs.com/ybbit)
* @date 2023-06-26 20:23
* @tags 喜欢就去努力的争取
*/
@Service
public class AccountService implements ApplicationListener<LoginSuccessEvent> {
public void addAccountScore(String username) {
System.out.println(username + "增加积分");
}
@Override
public void onApplicationEvent(LoginSuccessEvent event) {
UserEventEntity userEventEntity = (UserEventEntity) event.getSource();
System.out.println("============AccountService=============onApplicationEvent");
addAccountScore(userEventEntity.getUsername());
}
}
CouponService
package com.ly.service;
import com.ly.entity.UserEventEntity;
import com.ly.event.LoginSuccessEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
/**
* 优惠券
*
* @author ly (个人博客:https://www.cnblogs.com/ybbit)
* @date 2023-06-26 20:23
* @tags 喜欢就去努力的争取
*/
@Service
public class CouponService {
@EventListener
public void onEnvet(LoginSuccessEvent event) {
// TODO 判断逻辑......
UserEventEntity userEventEntity = (UserEventEntity) event.getSource();
System.out.println("=========CouponService========= onEnvet");
addCoupon(userEventEntity.getUsername());
}
public void addCoupon(String username) {
System.out.println(username + "发送优惠券");
}
}
SystemService
package com.ly.service;
import com.ly.entity.UserEventEntity;
import com.ly.event.LoginSuccessEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
/**
* 登录日志
*
* @author ly (个人博客:https://www.cnblogs.com/ybbit)
* @date 2023-06-26 20:23
* @tags 喜欢就去努力的争取
*/
@Service
public class SystemService {
@Order(1)
@EventListener
public void onEvent(LoginSuccessEvent event) {
System.out.println("==========SystemService========= onEvent");
UserEventEntity userEventEntity = (UserEventEntity) event.getSource();
addLoginLog(userEventEntity.getUsername());
}
public void addLoginLog(String username) {
System.out.println(username + "记录登录日志");
}
}
(5) 修改旧的登录处理逻辑
@Autowired
private EventPublisher eventPublisher;
@Autowired
private AccountService accountService;
@Autowired
private CouponService couponService;
@Autowired
private SystemService systemService;
@GetMapping("/login")
public String login(@RequestParam String username,
@RequestParam String password) {
/* // 伪代码
// login......
// 加积分
accountService.addAccountScore(username);
// 送优惠券
couponService.addCoupon(username);
// 记录登录日志
systemService.addLoginLog(username);
// 等等....*/
// 我们发送登录事件就好了
eventPublisher.sendEvent(new LoginSuccessEvent(new UserEventEntity(username, password)));
return "success";
}
3、事件监听的几种方式
1、在应用上下文直接添加
2、使用spring.factories文件
3、使用@EventListener注解
4、自定义监听器实现ApplicationListener接口并交给Spring管理
事件发布:ApplicationEventPublisherAware
或注入:ApplicationEventMulticaster
事件监听:组件 + @EventListener