spring中发布订阅模式实践
概述
在实际开发中,经常会碰到要去解耦合一些依赖调用,比如单成功后会发送手机短信、发送绑定邮箱、数据库更新后通知发送mq等。而且通知这个操作又不希望强耦合在主业务流程中,这个时候我们很容易就想到了发布订阅(观察者)设计模式。
首先看代码实现:
定义事件类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import org.springframework.context.ApplicationEvent;
public class MessageEvent extends ApplicationEvent {
private String message;
public MessageEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
}定义监听类
写法1:1
2
3
4
5
6
7
8
9
10
11
12
13import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
public class MessageListener implements ApplicationListener<MessageEvent> {
@Override
// @Async 开启异步执行
public void onApplicationEvent(MessageEvent messageEvent) {
System.out.println("用类监听到了消息:"+messageEvent.getMessage());
}
}写法二:
1
2
3
4
5
6
7
8
9
10
11
12
13
14import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
public class MessageListener2 {
@EventListener
// @Async 开启异步执行
public void messageListener(MessageEvent messageEvent) {
String message = messageEvent.getMessage();
System.out.println("用注解类监听到了消息:" + message);
}
}开启异步执行需要在启动类添加
@EnableAsync
注解1
2
3
4
5
6
7
8
9
10
11
12
13import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}定义事件发布类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18import com.example.demo.listener_demo.MessageEvent;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
@SpringBootTest
public class ListenerTest {
@Autowired
private ApplicationContext applicationContext;
@Test
public void listenerTest(){
applicationContext.publishEvent(new MessageEvent(this,"这是条消息。。。"));
System.out.println("消息发完了。。。");
}
}实践结果
未开始异步:
1
2
3
用类监听到了消息:这是条消息。。。
用注解类监听到了消息:这是条消息。。。
消息发完了。。。
开启异步:
1
2
3
消息发完了。。。
用类监听到了消息:这是条消息。。。
用注解类监听到了消息:这是条消息。。。
原理分析
事件
ApplicationEvent该抽象类继承自JDK的EventObject。JDK要求所有事件将继承它,并通过source得到事件源。
1 |
|
发布者
ApplicationEventPublisher及ApplicationEventMulticaster。ApplicationContext该接口继承了ApplicationEventPublisher,并在AbstractApplicationContext实现了具体代码,实际执行是委托给ApplicationEventMulticaster(可以认为是多播):
ApplicationContext继承自ApplicationEventPublisher
1 |
|
ApplicationEventPublisher定义了publishEvent方法:
1 |
|
在AbstractApplicationContext实现了具体代码,实际执行是委托给ApplicationEventMulticaster(可以认为是多播)
1 |
|
ApplicationContext自动到本地容器里找一个ApplicationEventMulticaster实现,如果没有自己new一个SimpleApplicationEventMulticaster。
1 |
|
可以看到如果给它一个executor(java.util.concurrent.Executor),它就可以异步支持发布事件了。所以发送事件只需要通过ApplicationContext.publishEvent即可
监听器
以ApplicationListener 为例:
ApplicationListener其继承自JDK的EventListener
1 |
|
总结
使用spring实现事件监听机制非常简单,涉及到者几个类文件 :ApplicationEvent(事件类型)、ApplicationListener(事件监听类)、ApplicationEventPublisher(事件发布类)。