事件监听-@TransactionalEventListener与@EventListener的介绍、区别和使用

发布于:2023-09-14 ⋅ 阅读:(150) ⋅ 点赞:(0)

前言

  如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。
  而且听说点赞的人每天的运气都不会太差,实在白嫖的话,那欢迎常来啊!!!


事件监听-@TransactionalEventListener与@EventListener的介绍、区别和使用

1. @EventListener 是什么?

@EventListener是Spring Framework中的注解,用于声明事件监听器方法。它用于将一个方法标记为事件监听器,并定义了该方法应该在接收到特定事件时被调用。

当使用@EventListener注解标记一个方法时,Spring会将该方法注册为一个事件监听器,并在事件发布时自动调用它。监听器方法通常被定义在Spring应用程序的各个组件中,例如Bean类、Service类等。

使用@EventListener注解时,方法的参数可以是事件对象,也可以是包含事件对象的包装对象。当事件被发布时,Spring会自动寻找匹配事件类型的监听器方法并调用它们。

2. @TransactionalEventListener 是什么?

@TransactionalEventListener 是一个注解,用于在Spring应用程序中声明事务事件监听器的方法。它是Spring Framework中的一项功能,用于简化基于事件的编程模型。

@TransactionalEventListener 注解可以应用在方法上,指示该方法是一个事务事件监听器。当触发指定类型的事件时,Spring将自动调用带有 TransactionalEventListener 注解的方法,并在事务上下文中执行该方法。

@TransactionalEventListener 注解可以配置以下属性:

  1. value:指定监听的事件类型,可以是单个事件类型或事件类型数组。
  2. fallbackExecution:指定是否使用回退执行模式。当事务存在且已经激活时,如果设置为 false,则监听器方法将不会在事务上下文中执行;如果设置为 true,则将回退到非事务执行。
  3. phase:指定方法的执行阶段。默认为 TransactionPhase.AFTER_COMMIT,表示在事务提交后执行方法,还可以选择
    TransactionPhase.BEFORE_COMMIT、
    TransactionPhase.AFTER_ROLLBACK和TransactionPhase.AFTER_COMPLETION。

@TransactionalEventListener 注解的使用可以方便地将事件处理与事务管理结合起来,确保事件监听器方法在适当的事务上下文中执行,并能够在事件处理过程中进行事务管理操作。

3. @TransactionalEventListener与@EventListener的缺点

3.1. @TransactionalEventListener 的缺点:

  • 依赖于事务管理:@TransactionalEventListener注解需要依赖于Spring的事务管理机制。如果应用程序中没有启用事务管理或未配置适当的事务管理器,@TransactionalEventListener注解可能无法正常工作。
  • 隐式事务传播:@TransactionalEventListener注解默认使用容器的默认事务传播行为,这可能导致意外的事务行为。如果不清楚事务传播的规则,可能会导致意外的结果。

3.2. @EventListener 的缺点:

  • 缺乏事务支持:@EventListener注解并没有直接支持事务处理。因此,如果需要在事件处理中进行事务管理或需要在特定事务上下文中执行事件处理逻辑,就无法直接通过 @EventListener 注解实现,需要使用其他手段来实现事务管理。
  • 无法处理异步事件:@EventListener注解默认是同步执行的,即事件发布和事件处理都在同一线程中。如果需要处理异步事件,需要借助其他异步处理机制,如使用Spring的异步方法或使用消息中间件等。

4. @EventListener与MQ的优缺点

4.1 @EventListener 的优缺点

优点:

  • 简单易用:使用 @EventListener 注解,开发人员可以轻松地将方法标记为事件监听器,无需额外的配置和复杂的代码。
  • 高内聚性:将事件和事件处理器放在同一个类中,可以提高代码的可读性和维护性。
  • 低耦合性:事件发布者和事件监听者之间没有直接依赖关系,它们通过事件进行解耦,可以方便地添加或删除事件处理器。
  • 异步处理:事件监听器可以使用多线程或异步任务来处理事件,从而提高应用程序的性能和响应能力。

缺点:

  • 限制于单个应用程序:@EventListener 适用于单个应用程序内部的事件处理,如果需要跨应用程序进行事件通信,就无法使用该机制。
  • 缺乏消息持久性:@EventListener 机制并没有提供消息持久性的特性,一旦事件发布后,如果没有监听者或监听者未能处理消息,消息将会丢失。

4.2 消息队列(MQ)的优缺点:

优点:

  • 异步通信:MQ 允许发布者将消息发送到队列中,而不需要等待消费者处理。这种异步通信方式可以提高系统的可伸缩性和吞吐量。
  • 可靠性:MQ 提供持久化机制,可以确保消息在发送过程中不会丢失,并且可以在消费者处理失败时进行重试。
  • 解耦和灵活性:通过将消息发布到队列中,不同的应用程序可以独立演化和扩展,它们只需要共享相同的消息格式和协议即可进行通信。
  • 可以跨应用程序使用:MQ 可以用于实现不同应用程序之间的集成和消息传递,使系统的各个组件能够松耦合地协同工作。

缺点:

  • 引入复杂性:使用 MQ 增加了系统的复杂性,需要额外的配置和管理 MQ 服务器。
  • 系统可用性依赖于 MQ:如果 MQ 服务器出现故障或性能问题,整个系统的可用性和性能可能会受到影响。
  • 增加了延迟:由于 MQ 是异步通信的机制,消息的传递和处理可能会引入一定的延迟。

5.@EventListener 示例

5.1. 事件监听类

    @Async
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT,classes = OneEvent.class)
    @Order(0)
    public void testOneEventHandler(OneEvent event) {
        log.info("=====================OneEvent===================:{}",event.getName());
    }

    @Async
    @EventListener(classes = TwoEvent.class)
    @Order(0)
    public void twoEventEventHandler(TwoEvent event) {
       log.info("=====================TwoEvent===================:{}",event.getName());

    }
    

5.2. 事件类:

@Getter
@Setter
@ToString
public class OneEvent extends ApplicationEvent {
    private String  name;
    public OneEvent() {
        super("OneEvent async message");
    }

    //======================================================
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}


@Getter
@Setter
@ToString
public class TwoEvent extends ApplicationEvent {
    private String  name;
    public TwoEvent() {
        super("TwoEvent async message");
    }

    //======================================================
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


}

5.3. 测试代码

Controller:

    @Autowired
    TestService service;
    @ApiOperation(value = "测试", notes = "测试")
    @CommonLog(methodName = "测试",className = "TestController#event")
    @RequestMapping(value = "/v1/event", method = RequestMethod.POST)
    public void event(){
        TwoEvent event1 = new TwoEvent();
        event1.setName("eiuyriuw");
        SpringContextUtil.getApplicationContext().publishEvent(event1);
        service.test();
    }

Service:

public interface TestService {

    void test();
}
@Service
@Slf4j
public class TestServiceImpl implements TestService {
    @Transactional
    @Override
    public void test() {
        OneEvent event = new OneEvent();
        event.setName("uiuoiuo");
        SpringContextUtil.getApplicationContext().publishEvent(event);
    }
}

5.4. 测试

调用测试代码
在这里插入图片描述

测试成功!!!


网站公告

今日签到

点亮在社区的每一天
去签到