springboot ApplicationEvent事件监听与异步

南城.南城 · 收录于 2023-11-30 21:21:41 · source URL

	ApplicationEvent以及Listener是Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式,设计初衷是为了系统业务逻辑解耦,提高可扩展性及可维护性。事件发布者并不需要考虑谁去监听,监听具体的内容是什么,监听者也不需要考虑事件是谁发布,只需要将接收到的事件完成即可,个人理解和mq的模式其实有些相似。
	从Spring 4.2以后,事件处理不用实现ApplicationListener 的 onApplicationEvent方法了,使用注解@EventListener可以自动关联相关的ApplicationListener。

下面是一段我在项目中用到的代码示例
需求:在用户发起订单投诉后像运营人员发送一条短信提示处理用户投诉,如果用户手机为华为手机则向用户发送一条负一屏消息提示已接到投诉正在处理。要求发送短息与负一屏消息不得影响主流程的正常流转。

定义event事件模型

首先定义一个event事件模型。ComplaintDTO为事件发布者传送给事件监听者的一些信息,入投诉的订单信息、客户信息等。可根据自身需要进行调整,调整之后需要变动相应的get/set方法和构造方法。

import org.springframework.context.ApplicationEvent;

public class ComplaintEvent extends ApplicationEvent {

    private ComplaintDTO complaintDTO;

    public ComplaintEvent(Object source,ComplaintDTO complaintDTO) {
        super(source);
        this.complaintDTO = complaintDTO;
    }

    public ComplaintDTO getComplaintDTO() {
        return complaintDTO;
    }

    public void setComplaintDTO(ComplaintDTO complaintDTO) {
        this.complaintDTO = complaintDTO;
    }
}

发布事件

@Autowired
private ApplicationEventPublisher applicationEventPublisher;

@Override
public ComplaintVO createComplaint(ComplaintDTO complaintDTO) {
    //TODO 你的业务代码
    //发负一屏消息和短信
    try{
        ComplaintEvent complaintEvent = new ComplaintEvent(this,complaintDTO);
        applicationEventPublisher.publishEvent(complaintEvent);
    }catch (Exception e){
        log.info("投诉发短信或负一屏消息失败:[{}]",e.getMessage());
    }
    vo = Transferor.entity(po, ComplaintVO.class);
    return vo;
}

事件监听者

事件的监听者实现ApplicationListener接口,重写onApplicationEvent方法实现事件处理
这里需要注意的是ApplicationEvent默认并不是异步的,如果需要异步需要我们在方法上加上@Async注解,并在启动类添加@EnableAsync开启异步

@Log4j2
@Component
public class ComplaintEventListener implements ApplicationListener<ComplaintEvent> {
    @Async
    @Override
    public void onApplicationEvent(ComplaintEvent event) {
        log.info("订单投诉发短信与负一屏消息:[{}]", JSON.toJSONString(event));
        //发短信
        try {
            sendSmsMsg(event);
        }catch (Exception e){
            log.info("订单投诉发短信失败:[{}]",e.getMessage());
        }
        //发负一屏消息
        try {
            sendHwPubMsg(event);
        }catch (Exception e){
            log.info("订单投诉发负一屏消息失败:[{}]",e.getMessage());
        }
    }
}

从Spring 4.2以后,事件处理不用实现ApplicationListener 的 onApplicationEvent方法了,使用注解@EventListener可以自动关联相关的ApplicationListener。
所以上面的代码其实可以改成成下面的样子

@Log4j2
@Component
public class ComplaintEventListener{
    @Async
    @EventListener
    public void sendMsg(ComplaintEvent event) {
        log.info("订单投诉发短信与负一屏消息:[{}]", JSON.toJSONString(event));
        //发短信
        try {
            sendSmsMsg(event);
        }catch (Exception e){
            log.info("订单投诉发短信失败:[{}]",e.getMessage());
        }
        //发负一屏消息
        try {
            sendHwPubMsg(event);
        }catch (Exception e){
            log.info("订单投诉发负一屏消息失败:[{}]",e.getMessage());
        }
    }
}

另外 ApplicationEvent还能控制事务,这里有一篇大佬写的非常详细的
使用@TransactionalEventListener处理数据库事务提交成功后再执行操作