基于 Spring 实现观察者模式

文章介绍了观察者模式的概念及其在Spring框架中的应用。Spring的事件机制基于观察者模式,通过ApplicationEvent、ApplicationEventPublisher和ApplicationListener接口实现事件的发布和监听。文章以用户注册为例,展示了如何定义自定义事件、发布事件以及创建监听器来处理事件,强调了Spring事件机制在系统扩展性和解耦方面的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

前言

一、什么是观察者模式?

二、Spring的事件机制

三、Spring的事件应用扩展


前言

当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。


一、什么是观察者模式?

观察者模式又称为 发布-订阅模式,定义了对象之间一对多依赖关系,当目标对象(被观察者)的状态发生改变时,它的所有依赖者(观察者)都会收到通知。一个观察目标可以对应多个观察者,而这些观察者之间没有相互联系,所以能够根据需要增加和删除观察者,使得系统更易于扩展,符合开闭原则;并且观察者模式让目标对象和观察者松耦合,虽然彼此不清楚对方的细节,但依然可以交互,目标对象只知道一个具体的观察者列表,但并不认识任何一个具体的观察者,它只知道他们都有一个共同的接口。

电商领域的一个典型应用场景是,当用户注册成功以后,需要给用户发送短信,邮件 和优惠券信息。
 

二、Spring的事件机制

  • ApplicationEvent:通过继承它,实现自定义事件。另外,通过它的 source 属性可以获取事件源,timestamp 属性可以获得发生时间。
  • ApplicationEventPublisher:通过实现它,来发布变更事件。
  • ApplicationEventListener:通过实现它,来监听指定类型事件并响应动作。

ApplicationEvent 源代码

public abstract class ApplicationEvent extends EventObject {
    private static final long serialVersionUID = 7099057708183571937L;
    private final long timestamp = System.currentTimeMillis();

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

    public final long getTimestamp() {
        return this.timestamp;
    }
}

 ApplicationEventPublisherAware 源代码

package org.springframework.context;

import org.springframework.beans.factory.Aware;

public interface ApplicationEventPublisherAware extends Aware {
    void setApplicationEventPublisher(ApplicationEventPublisher var1);
}

 ApplicationListener源代码

package org.springframework.context;

import java.util.EventListener;

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    void onApplicationEvent(E var1);
}

三、Spring的事件应用扩展

定义自己的 事件 类:Event

public interface Event extends DTO {
}

定义事件发布接口类:Publisher

/**
 * 消息事件发布接口
 *
 * @author yangyanping
 * @date 2022-12-22
 */
public interface Publisher<E extends Event> {
    /**
     * 发布同步事件
     */
    void publishSync(E event);

    /**
     * 发布异步事件
     */
    void publishAsync(E event);
}

这里就以上面的用户注册为例,来看看代码示例。首先定义用户注册事件 UserRegisterEvent。UserService 在完成自身的用户注册逻辑之后,仅仅只需要发布一个 UserRegisterEvent 事件,而无需关注其它拓展逻辑。其它 Service 可以自己订阅 UserRegisterEvent 事件,实现自定义的拓展逻辑。 

public class UserRegisterEvent extends ApplicationEvent implements Event {
    /**
     * 用户名
     */
    @Getter
    private String username;

    public UserRegisterEvent(Object source, String username) {
        super(source);
        this.username = username;
    }
}

然后定义用户注册事件发布UserRegisterPublisher类,实现 ApplicationEventPublisherAware 接口,从而将 ApplicationEventPublisher 注入进来。从下面代码可以看到,在执行完注册逻辑后,调用了 ApplicationEventPublisher的 publishEvent(ApplicationEvent event) 方法,发布了 UserRegisterEvent 事件。

/**
 * 用户注册事件发布
 * @author yangyanping
 * @date 2023-06-27
 */
@Component
public class UserRegisterPublisher implements Publisher<UserRegisterEvent>, ApplicationEventPublisherAware {
    private ApplicationEventPublisher applicationEventPublisher;

    /**
     * 同步发送事件
    */
    @Override
    public void publishSync(UserRegisterEvent event) {
        applicationEventPublisher.publishEvent(event);
    }

     /**
     * 异步发送事件
     */
    @Async
    @Override
    public void publishAsync(UserRegisterEvent event) {
        applicationEventPublisher.publishEvent(event);
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
}

创建UserMailListener 监听器,实现 ApplicationListener 接口,通过 E 泛型设置感兴趣的事件,实现 onApplicationEvent(E event) 方法,针对监听的 UserRegisterEvent 事件,进行自定义处理。 

/**
 * 用户短信发送监听器
 *
 * @author yangyanping
 * @date 2023-06-27
 */
@Slf4j
@Component
public class UserMailListener implements ApplicationListener<UserRegisterEvent> {
    

    @Override
    public void onApplicationEvent(UserRegisterEvent event) {
    }
}

创建用户邮件UserEmailListener 监听器,不同于上面的实现 ApplicationListener 接口方式,在方法上,添加 @EventListener 注解,并设置监听的事件为 UserRegisterEvent。这是另一种使用方式。

/**
 * 用户邮件发送监听器
 *
 * @author yangyanping
 * @date 2023-06-27
 */
@Slf4j
@Component
public class UserEmailListener  {
    

    @EventListener 
    public void sendMail(UserRegisterEvent event) {
    }
}

 创建用户服务 UserService ,完成用户注册 和 用户注册事件发送 。

@Service
public class UserService  { 
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Resource
    private UserRegisterPublisher publisher;

    public void register(String username) {
        // ... 执行注册逻辑
        logger.info("[register][执行用户({}) 的注册逻辑]", username);
        // ... 发布用户注册事件
        publisher.publishSync(new UserRegisterEvent(this, username));
    }
}

看到这里,细心的同学可能想到了发布订阅模式,其实观察者模式于发布订阅还是有区别的,简单来说,发布订阅模式属于广义上的观察者模式,在观察者模式的 Subject 和 Observer 的基础上,引入 Event Channel 这个中介,进一步解耦。观察者模式更加轻量,通常用于单机,而发布订阅模式相对而言更重一些,通常用于分布式环境下的消息通知场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值