springboot发布订阅(事件)@TransactionalEventListener,ApplicationEvent,ApplicationEventPublisherAware应用

定义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());
}

可以更加灵活

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值