Spring之观察者模式

基于SpringBoot2

1. 概念

观察者模式 (Observer Pattern) :定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。

观察者模式包含观察目标和观察者两类对象,一个目标可以有任意数目的与之相依赖的观察者,一旦观察目标的状态发生改变,所有的观察者都将得到通知

它也叫发布订阅模式(Publish/Subscibe)

image-20210717193849319

它的好处就是解耦,订阅者无需关心发布者做了什么,接收到通知做事就行了

在 MQ 或者 Redis 等中间件中也都有发布订阅的实现

2. 使用场景

说到观察者模式很多可能不太清楚,但是说发布订阅就很清晰

比如一个微信公众号,大佬发了一篇文章,关注他的人都会收到文章推送,这就是发布订阅

再如用户注册后给用户发送短信邮件通知,这是两个不同的业务,我们可以进行解耦

再如视频会员过期前给你推送消息提醒

在现实生活中观察者模式处处可见

3. Spring中观察者模式的四个角色

3.1 事件(ApplicationEvent)

ApplicationEvent 是所有事件对象的父类。ApplicationEvent 继承自 jdk 的 EventObject, 所有的事件都需要继承 ApplicationEvent, 并且通过 source 得到事件源

image-20210717201845046

Spring 内置的四个事件,他们都是 ApplicationEvent 的子类,通过监听这四个组件我们可以在 ApplicationContext 启动刷新停止关闭时做一些操作

image-20210717202821493

3.2 事件监听(ApplicationListener)

ApplicationListener 事件监听器,也就是观察者。继承自 jdk 的 EventListener,该类中只有一个方法 onApplicationEvent。当监听的事件发生后该方法会被执行。

image-20210717203205853

3.3 事件发布(ApplicationContext)

ApplicationContext 是 Spring 中的核心容器,在事件监听中 ApplicationContext 可以作为事件的发布者,也就是事件源。因为 ApplicationContext 继承自 ApplicationEventPublisher。在 ApplicationEventPublisher 中定义了事件发布的方法 — publishEvent(Object event)

image-20210717203423165

3.4 事件管理(ApplicationEventMulticaster)

ApplicationEventMulticaster 用于事件监听器的注册和事件的广播。监听器的注册就是通过它来实现的,它的作用是把 Applicationcontext 发布的 Event 广播给它的监听器列表‘

image-20210717203514981

4. 使用

4.1 自定义事件

继承 ApplicationEvent 即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import lombok.Getter;
import org.springframework.context.ApplicationEvent;

/**
* @author dream.
* @description: TODO 类描述
* @date 2021/5/6
**/
@Getter
public class TaskEvent extends ApplicationEvent {
private final boolean execution;

/**
* Create a new {@code ApplicationEvent}.
*
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
*/
public TaskEvent(Object source, boolean execution) {
super(source);
this.execution = execution;
}
}

4.2 事件发布

我们可以使用 ApplicationEventPublisher 来发布事件,或者使用 ApplicationContext 也可以

1
2
3
4
5
6
   @Autowired
private ApplicationEventPublisher applicationEventPublisher;

public void publish(){
applicationEventPublisher.publishEvent(new TaskEvent(this, true));
}

4.3 事件监听

4.3.1 实现 ApplicationListener 接口进行监听

image-20210717204501289

当我们发布者发布事件时这边就会监听到 TaskEvent 事件

4.3.2 使用 @EventListener 注解进行监听

image-20210717204816576

4.3.3 条件监听

image-20210717205248110

@EventListener 注解中有三个值,value 和 classes 都是为了指定监听的事件,可以不用写,在方法参数指定,@AliasFor顾名思义就是取别名,在 spring 中value是默认值,比如这样

1
@EventListener(TaskEvent.class)

这个时候我们就不知道 value 是干啥的了,取了别名后我们就能知道它是要监听的事件的 class

@AliasFor 标签使用限制:

  • 互为别名的属性属性值类型,默认值,都是相同的,且必须设置默认值
  • 为别名的注解必须成对出现,比如 value 属性添加了@AliasFor](“classes”),那么 path 属性就必须添加 @AliasFor(“value”);

condition 属性是设置监听条件,支持SpEL表达式[1]

image-20210717210347245

监听 TaskEvent 事件,execution 为 true 时才调用方法

4.3.4 异步监听

配合 @Async 注解可以实现异步监听,不阻塞主线程,提高程序效率,使用 @Async 需要使用 @EnableAsync 注解来开启异步支持

image-20210717211603187

不再需要声明事务,因为Spring中的事务默认是和线程绑定的,当新启动一条线程时,将开启另一个独立的事务

4.3.5 事务回调监听

在上面使用 @EventListener 对事件进行监听,这时候是和我们发布者业务在一个事务内的,拿用户注册来说,注册后发邮件给用户,我们写一个监听事件去发邮件,如果说发邮件后,代码出错了,那此时事务就会回滚,但是邮件已经发出去了,那不太合适

这时候就需要用到 @TransactionalEventListener 了,看名字就知道它是 @EventListener 的升级版!他可以配合事务,在不同的事务阶段去监听

image-20210717213324601

我们可以看到它的增强属性,首先我们可以看下事务绑定的几个阶段,默认就是 TransactionPhase.AFTER_COMMIT

image-20210717213701869

在我们上面的例子中我们需要在事务提交后给用户发送邮件,这个时候就派上用场了

再来看看 fallbackExecution 属性的作用,官方注释写的很明白,如果没有事务正在运行,是否应该处理事件,默认值为 false ,那就是不处理

image-20210717214138537

5. 参考