Spring发布订阅模式详解

Spring 的发布订阅模式(Publish-Subscribe Pattern)是一种基于事件驱动的设计模式,通过 "事件" 作为中间载体实现组件间的解耦。在这种模式中,"发布者"(Publisher)负责产生事件并发布,"订阅者"(Subscriber)通过订阅特定事件接收通知并处理,两者无需直接依赖,从而降低系统耦合度。

一、核心概念与角色

Spring 的发布订阅模式主要涉及三个核心角色:

  1. 事件(Event)
    事件是发布者与订阅者之间的通信载体,封装了需要传递的数据。在 Spring 中,所有事件都需继承ApplicationEvent(Spring 4.2 + 后可省略继承,直接使用普通类作为事件)。

  2. 发布者(Publisher)
    负责创建并发布事件的组件。Spring 中通过ApplicationEventPublisher接口(或其实现类,如ApplicationContext)来发布事件,调用publishEvent()方法即可。

  3. 订阅者(Subscriber)
    负责监听并处理特定事件的组件。Spring 中订阅者可通过实现ApplicationListener接口,或使用@EventListener注解定义事件处理方法。

二、Spring 事件机制的核心组件

1. ApplicationEvent(事件基类)

ApplicationEvent是 Spring 事件的基类,继承自 JDK 的EventObject,包含事件源(source)和事件发生时间(timestamp)。

// Spring内置的ApplicationEvent
public abstract class ApplicationEvent extends EventObject {
    private final long timestamp; // 事件发生时间
    
    public ApplicationEvent(Object source) {
        super(source);
        this.timestamp = System.currentTimeMillis();
    }
    
    public final long getTimestamp() {
        return this.timestamp;
    }
}

自定义事件示例
通常通过继承ApplicationEvent定义业务事件:

// 自定义用户注册事件
public class UserRegisteredEvent extends ApplicationEvent {
    private User user; // 事件中携带的用户数据
    
    public UserRegisteredEvent(Object source, User user) {
        super(source);
        this.user = user;
    }
    
    public User getUser() {
        return user;
    }
}

Spring 4.2 + 后支持非继承 ApplicationEvent 的事件,直接使用普通类即可:

// 无需继承ApplicationEvent的事件
public class OrderCreatedEvent {
    private Order order;
    // 构造器、getter等
}
2. ApplicationListener(订阅者接口)

ApplicationListener是订阅者的核心接口,用于定义事件处理逻辑,泛型参数指定需要监听的事件类型。

// Spring的事件监听器接口
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    // 事件处理方法,当监听的事件被发布时调用
    void onApplicationEvent(E event);
}

实现接口的订阅者示例

// 监听UserRegisteredEvent的订阅者(发送欢迎邮件)
@Component
public class WelcomeEmailListener implements ApplicationListener<UserRegisteredEvent> {
    @Override
    public void onApplicationEvent(UserRegisteredEvent event) {
        User user = event.getUser();
        System.out.println("给用户" + user.getName() + "发送欢迎邮件...");
    }
}
3. ApplicationEventPublisher(发布者接口)

ApplicationEventPublisher是发布事件的接口,定义了发布事件的方法:

public interface ApplicationEventPublisher {
    // 发布事件
    void publishEvent(ApplicationEvent event);
    
    // Spring 4.2+新增,支持发布非ApplicationEvent类型的事件
    void publishEvent(Object event);
}

发布者的实现
Spring 的ApplicationContext(容器本身)实现了ApplicationEventPublisher接口,因此可直接通过容器发布事件。实际开发中,通常通过依赖注入ApplicationEventPublisherApplicationContext来发布事件:

@Service
public class UserService {
    // 注入事件发布器
    @Autowired
    private ApplicationEventPublisher publisher;
    
    public void register(User user) {
        // 1. 执行注册逻辑
        System.out.println("用户" + user.getName() + "注册成功");
        
        // 2. 发布用户注册事件
        publisher.publishEvent(new UserRegisteredEvent(this, user));
    }
}

三、注解驱动的事件监听(@EventListener)

Spring 4.2 引入@EventListener注解,无需实现ApplicationListener接口,直接在方法上标注即可定义事件处理逻辑,更简洁灵活。

基本用法
@Component
public class UserEventHandler {
    // 监听UserRegisteredEvent事件
    @EventListener
    public void handleUserRegisteredEvent(UserRegisteredEvent event) {
        User user = event.getUser();
        System.out.println("处理用户注册事件:" + user.getName());
    }
    
    // 监听多个事件(方法参数为多个事件类型)
    @EventListener
    public void handleMultiEvents(UserRegisteredEvent userEvent, OrderCreatedEvent orderEvent) {
        // 处理逻辑
    }
}
条件监听(condition)

通过condition属性指定 SpEL 表达式,满足条件时才执行监听逻辑:

@EventListener(condition = "#event.user.age > 18") // 只处理成年用户的注册事件
public void handleAdultUserRegistered(UserRegisteredEvent event) {
    // 处理逻辑
}
事件顺序(@Order)

多个监听器监听同一事件时,通过@Order指定执行顺序(值越小越先执行)

@Order(1) // 先执行
@EventListener
public void handleFirst(UserRegisteredEvent event) { ... }

@Order(2) // 后执行
@EventListener
public void handleSecond(UserRegisteredEvent event) { ... }

四、异步事件处理

默认情况下,Spring 事件处理是同步的:发布者发布事件后,会等待所有监听器处理完成才继续执行。若需异步处理(不阻塞发布者),可通过以下步骤实现:

  1. 启用异步支持:在配置类上添加@EnableAsync注解。
  2. 标注异步方法:在监听方法上添加@Async注解。

示例:

// 1. 配置类启用异步
@Configuration
@EnableAsync
public class AsyncConfig {
    // 可选:自定义线程池
    @Bean
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        executor.initialize();
        return executor;
    }
}

// 2. 异步处理事件的监听器
@Component
public class AsyncUserListener {
    @Async // 异步执行
    @EventListener
    public void handleAsync(UserRegisteredEvent event) {
        System.out.println("异步处理事件:" + Thread.currentThread().getName());
        // 耗时操作(如发送短信、调用第三方接口等)
    }
}

五、事务绑定事件(@TransactionalEventListener)

在业务中,常需要在事务完成后(提交 / 回滚)再处理事件(例如:订单事务提交后再发送通知)。Spring 提供@TransactionalEventListener注解,支持绑定事务生命周期。

注解的phase属性指定事务阶段:

  • AFTER_COMMIT:事务提交后(默认)
  • AFTER_ROLLBACK:事务回滚后
  • AFTER_COMPLETION:事务完成后(无论提交还是回滚)
  • BEFORE_COMMIT:事务提交前

示例:

@Service
public class OrderService {
    @Autowired
    private ApplicationEventPublisher publisher;
    
    @Transactional
    public void createOrder(Order order) {
        // 保存订单(事务内操作)
        orderRepository.save(order);
        // 发布事件(实际处理会在事务提交后)
        publisher.publishEvent(new OrderCreatedEvent(order));
    }
}

@Component
public class OrderEventListener {
    // 订单事务提交后才处理事件
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void handleOrderCreated(OrderCreatedEvent event) {
        System.out.println("订单" + event.getOrder().getId() + "已提交,发送通知...");
    }
}

六、事件传播机制

Spring 事件具有层次性:监听器可监听父类事件,从而接收所有子类事件。例如:

  • ApplicationEvent是所有事件的父类,监听ApplicationEvent的监听器会接收所有类型的事件。
  • 自定义事件UserEvent的子类UserRegisteredEventUserDeletedEvent,监听UserEvent的监听器会接收这两个子类事件。

七、应用场景

Spring 发布订阅模式适用于以下场景:

  1. 业务解耦:例如用户注册后,需要发送邮件、积分初始化、日志记录等操作,通过事件分离这些逻辑,避免注册服务与其他服务直接耦合。
  2. 异步通知:耗时操作(如短信发送、报表生成)通过异步事件处理,不阻塞主流程。
  3. 状态变更通知:如订单状态变更后,通知库存、支付、物流等相关模块。
  4. 跨组件通信:不同模块(如 Controller、Service、Repository)通过事件交互,无需直接依赖。

总结

Spring 的发布订阅模式基于事件驱动,通过ApplicationEventApplicationListenerApplicationEventPublisher三大组件实现,配合@EventListener@Async@TransactionalEventListener等注解,提供了灵活、解耦的组件通信方式。其核心价值在于降低组件间耦合度,提高系统的可扩展性和可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值