从注解@EventListener和@TransactionalEventListener掌握Spring的事件机制原理

Spring事件监听机制

Spring事件监听机制概述

Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式;为的就是业务系统逻辑的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现内容是什么,发布者的工作只是为了发布事件而已。

在Spring中我们可以通过实现ApplicationListener接口或者@EventListener接口来实现事件驱动编程。

比如我们做一个电商系统,用户下单支付成功后,我们一般要发短信或者邮箱给用户提示什么的,这时候就可以把这个通知业务做成一个单独事件监听,等待通知就可以了;把它解耦处理。
从注解@\EventListener和@\TransactionalEventListener掌握Spring的事件机制原理 - Java技术债务

Spring事件监听机制介绍

Spring事件相关的几个类

Spring事件类 自定义类 描述
org.springframework.context.ApplicationContext 运行程序上下文
org.springframework.context.ApplicationListener AbstractEventListener 事件监听器接口
org.springframework.context.ApplicationEvent AbstractEvent 事件对象的父类
org.springframework.context.event.ApplicationEventMulticaster 发布事件的接口
org.springframework.context.event.SimpleApplicationEventMulticaster 发布事件的简单实现类

使用硬编码简单还原Spring事件机制

  • 自定义事件,需要继承ApplicationEvent

  • 自定义事件监听器,需要实现ApplicationListener接口,这个接口有个方法onApplicationEvent需要实现,用来处理相关的事件。

    public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
         
         
        /**
         * Handle an application event.
         * @param event the event to respond to
         */
        void onApplicationEvent(E event);
    }
    
  • 创建事件广播器

    创建事件广播器ApplicationEventMulticaster,这是个接口,你可以自己实现这个接口,也可以直接使用系统给我们提供的SimpleApplicationEventMulticaster,如下:

    ApplicationEventMulticaster applicationEventMulticaster = new SimpleApplicationEventMulticaster();
    
    
  • 向广播器中注册事件监听器

    将事件监听器注册到广播器ApplicationEventMulticaster中,如:

    ApplicationEventMulticaster applicationEventMulticaster = new SimpleApplicationEventMulticaster();
    applicationEventMulticaster.addApplicationListener(new SendEmailOnOrderCreateListener());
    
    
  • 通过广播器发布事件

    广播事件,调用ApplicationEventMulticaster#multicastEvent方法广播事件,此时广播器中对这个事件感兴趣的监听器会处理这个事件。

    applicationEventMulticaster.multicastEvent(new OrderCreateEvent(applicationEventMulticaster, 1shiL));
    

Spring事件机制正确的使用方式

Spring事件创建

创建一个抽象接口AbstractEventListener,继承ApplicationListener 接口

public abstract class AbstractEvent extends ApplicationEvent {
   
   

    public AbstractEvent(Object source) {
   
   
        super(source);
    }
}

创建自定义事件类TestEvent

@Getter
public class TestEvent  extends AbstractEvent{
   
   
    private Integer test;
    public TestEvent(Object source, Integer test) {
   
   
        super(source);
        this.test = test;
    }
}

Spring事件发布方式

  • 第一种方式:实现ApplicationEventPublisherAware接口,如果是老项目改动比较大,不建议使用。

    通常情况下,我们会使用以ApplicationContext结尾的类作为Spring的容器来启动应用

从注解@\EventListener和@\TransactionalEventListener掌握Spring的事件机制原理 - Java技术债务

说明了`AbstractApplicationContext`内部已经集成了事件广播器`ApplicationEventMulticaster`,说明`AbstractApplicationContext`内部是具体事件相关功能的,这些功能是通过其内部的`ApplicationEventMulticaster`来实现的,也就是说将事件的功能委托给了内部的`ApplicationEventMulticaster`来实现。

### ApplicationEventPublisher接口

上面类图中多了一个新的接口`ApplicationEventPublisher`,来看一下源码

```java
public interface ApplicationEventPublisher {

    default void publishEvent(ApplicationEvent event) {
        publishEvent((Object) event);
    }

    void publishEvent(Object event);
}

```

这个接口用来发布事件的,内部定义2个方法都是用来发布事件的。

### 获取ApplicationEventPublisher对象

如果我们想在普通的bean中获取`ApplicationEventPublisher`对象,需要实现`ApplicationEventPublisherAware`接口

```java
public interface ApplicationEventPublisherAware extends Aware {
    void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher);
}
```

Spring容器会自动通过上面的`setApplicationEventPublisher`方法将`ApplicationEventPublisher`注入进来,此时我们就可以使用这个来发布事件了。
  • 第二种方式:使用Spring容器中ApplicationContext 容器。建议使用。

    在Spring中的**ApplicationContext容器支持对事件的发布,本质和第一种方式一样,因为ApplicationContext 接口继承ApplicationEventPublisher 进行发布事件的。**

    /**
     * 异步事件发送
     *
     * @author Java技术债务
     * @date 2021/2/5
     */
    @Service
    public class EventPublisher {
         
         
    
        @Autowired
        private ApplicationContext applicationContext;
    
        /**
         * 发送异步事件
         *
         * @param event e
         */
        public void publishEvent(ApplicationEvent event) {
         
         
            applicationContext.publishEvent(event);
        }
    }
    

    原理:无论哪种方式最终都是由ApplicationEventMulticaster接口的实现类SimpleApplicationEventMulticaster进行发布并执行事件。

    public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
         
         
    	... ...
    	@Override
    	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
         
         
    		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    		Executor executor = getTaskExecutor();
    		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
         
         
    			if (executor != null) {
         
         
    				executor.execute(() -> invokeListener(listener, event));
    			}
    			else {
         
         
    				invokeListener(listener, event);
    			
Spring框架提供了一系列注解用于处理事件机制,其中`@EventListener``@TransactionalEventListener`都是在特定场景下使用的。下面是对这两个注解的详细介绍: ### @EventListener `@EventListener`是一个用于监听特定类型的事件(例如来自`ApplicationEventPublisher`、`Message`、`ContextRefreshedEvent`等)的注解。它可以应用于方法上,当指定事件发生时,该方法会被触发执行。这是Spring事件驱动架构的基本组成部分之一。 #### 使用示例: ```java import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.stereotype.Component; @Component public class MyEventListener implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { // 在这里执行事件相关的操作 System.out.println("应用程序已经刷新并准备好接收数据"); } } ``` ### @TransactionalEventListener `@TransactionalEventListener`与`@EventListener`类似,但是它还增加了事务管理的功能。这个注解允许你在监听事件的同时保证交易的原子性,即要么所有的操作都成功完成,要么都不执行。 #### 主要特点: - **事务管理**:当你在一个方法中使用了`@TransactionalEventListener`,Spring将自动在这个方法运行时创建一个新的事务。如果方法正常结束,则事务提交;如果方法抛出异常,则事务回滚。 - **易于整合**:这种方式简化了在处理事件时需要手动管理事务的过程,使得应用在处理异步事件时仍能保持一致性。 #### 使用示例: ```java import org.springframework.transaction.annotation.Transactional; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class TransactionalEventListener { @EventListener @Transactional public void handleEvent(MyCustomEvent event) { // 这里执行事件处理,并假设存在一些业务逻辑操作 System.out.println("处理自定义事件:" + event.getMessage()); } } ``` 注意:这里的`MyCustomEvent`应该是实际自定义事件的类实例。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java技术债务

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值