定义Event事件
通过集成ApplicationEvent
编写自定义事件属性
注意需要实现父类的构造函数,传入事件来源,既事件发起者
public class RegisterEvent extends ApplicationEvent {
private String user;
public RegisterEvent(Object source, String user) {
super(source);
this.user = user;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
}
编写监听器
方式一:
监听事件,springboot发布事件之后,监听器会拿到对应的事件Event类,并做相应处理
通过在方法上添加@EventListener注解声明监听器,在方法的形参中传入监听的事件Event
注意方法需要在springboot容器中,可以通过@Component注解讲类注入容器中
@EventListener
public void SendSms(RegisterEvent event){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("发送短信给用户:" + event.getUser());
}
方式二:
实现ApplicationListener接口,并实现其中的onApplicationEvent方法,指定需要监听的事件
@Component
public class EventListenerComponent implements ApplicationListener<RegisterEvent> {
@Override
public void onApplicationEvent(RegisterEvent event) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("发送短信给用户:" + event.getUser());
}
}
发布事件
发布事件需要实现ApplicationEventPublisherAware接口,通过ApplicationEventPublisherAware接口中注入的ApplicationEventPublisher类的publishEvent方法
实现ApplicationEventPublisherAware接口需要实现他的setApplicationEventPublisher方法
通过这个方法将ApplicationEventPublisher注入,就可以通过他发布事件了
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
@Component
public class MyEventPublisher implements ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
public void publishEvent(Object source, String event){
applicationEventPublisher.publishEvent(new RegisterEvent(source, event));
}
}
在Service层就可以通过调用Publisher的方法发布事件了
public void doOne() {
//注册
this.register();
//发送短信通知
//smsService.sentSms("zhangsan");
//发送优惠卷
couponService.pushCoupon("zhangsan");
//发布事件
myEventPublisher.publishEvent(this, "zhangsan");
}
@EventListener
刚刚提到的声明事件监听器可以通过@EventListener注解
这个注解的作用是在发布事件者发布事件之后,就能够监听到事件,然后执行自己的任务,这个过程是在事件发布者线程执行的,也就是跟事件发布者是串行的
比如上面的doOne方法,在完成了所有方法内的业务之后,还需要所有等待其他串行监听器完成工作并且成功返回,doOne方法才会返回,并且应为是一个线程,所以监听器的异常可能会上抛到业务层
如果是需要串行执行的业务场景可以使用@EventListener
如果业务场景不想影响到原来的主业务,例如注册功能,我想在注册之后,添加发放优惠卷,这个发放优惠卷又不想影响主业务,则需要调整上面的代码
例如
@Transactional(rollbackFor = Exception.class)
public void register() {
//注册
this.register();
//发布事件 ->发送优惠卷
myEventPublisher.publishEvent(this, "zhangsan");
}
@EventListener
public void PushCoupon(RegisterEvent event){
//发放优惠卷
}
如果是上面这种形式,如果在发放优惠卷的业务中,因为一些原因导致出现了异常,导致异常到了上游的业务层,最终会导致注册业务的失败,而且在注册业务完成之后,还会影响整个的业务响应时间
第一种处理方式是使用异步,将监听器的方法放入线程池中,或者提交到异步
可以使用springboot的@Async注解
@Async("mainPool")
@EventListener
public void PushCoupon(RegisterEvent event){
//发放优惠卷
}
这样之前的问题都没有了,但是出现了一个新的问题
如果是简单的业务处理,不会有什么问题,但是在业务复杂的情况下就出现了问题
@Transactional(rollbackFor = Exception.class)
public void doOne() {
//注册
this.register();
//发布事件 -> 发送短信通知
myEventPublisher.publishEvent(this, "zhangsan");
//创建账户
//生成OA系统账号
//...
}
如果是类似的业务逻辑,时间不是在最后所有的完成之后发布的,在我注册代码运行完之后,发布了事件,发送短信的异步事件已经启动了,并且在创建OA账号的过程中,短信已经发送成功了,但是创建OA账号失败了,用户又收到了成功的短信,避免这种情况可以使用下面这个注解
@TransactionalEventListener
通过这个注解声明监听器,可以让发送者的业务整个完成并且提交之后,在执行
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void SendSms(RegisterEvent event){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("发送短信给用户:" + event.getUser());
}
可以更加灵活