Spring 观察者模式使用
1.概述
在设计模式中,观察者模式是一个比较常用的设计模式。维基百科解释如下:
观察者模式是软件设计模式的一种。在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。
此种模式通常被用来实时事件处理系统。
在我们日常业务开发中,观察者模式对我们很大的一个作用,在于实现业务的解耦。以用户注册的场景来举例子,假设在用户注册完成时,需要给该用户发送邮件、发送优惠劵等等操作,如下图所示:
- UserService 在完成自身的用户注册逻辑之后,仅仅只需要发布一个 UserRegisterEvent 事件,而无需关注其它拓展逻辑。
- 其它 Service 可以自己订阅 UserRegisterEvent 事件,实现自定义的拓展逻辑。
友情提示:很多时候,我们会把观察者模式和发布订阅模式放在一起对比。
简单来说,发布订阅模式属于广义上的观察者模式,在观察者模式的 Subject 和 Observer 的基础上,引入 Event Channel 这个中介,进一步解耦。如下图所示:
2.Spring 事件机制
Spring 基于观察者模式,实现了自身的事件机制,由三部分组成:
- 事件 ApplicationEvent:通过继承它,实现自定义事件。另外,通过它的 source 属性可以获取事件源, timestamp 属性可以获取发生事件。
- 事件发布者 ApplicationEventPublisher:通过实现它,可以进行事件的发布,也可以实现ApplicationContentAware。
- 事件监听器 ApplicationListener:通过实现它,进行指定类型的事件的监听。
友情提示:JDK 也内置了事件机制的实现,考虑到通用性,Spring 的事件机制是基于它之上进行拓展。因此,ApplicationEvent 继承自
java.util.EventObject
,ApplicationListener 继承自java.util.EventListener
3.入门示例
SpringEvent 的使用
- 创建消息对象的实体类 (该类需要继承ApplicationEvent)
public class DemoEvent extends ApplicationEvent {
private static final long serialVersionUID = 5613108322901123046L;
@Getter
@Setter
private Long id;
@Getter
@Setter
private String message;
public DemoEvent(Object source, Long id, String message) {
super(source);
this.id = id;
this.message = message;
}
}
- 创建生产者
生产者类需要实现ApplicationContextAware接口来注入ApplicationContext对象
@Slf4j
@Component
public class DemoEventPublisher implements ApplicationEventPublisherAware {
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
public void publish(Long id, String message) {
log.info("做一些业务处理");
publisher.publishEvent(new DemoEvent(this, id, message));
}
}
- 创建消费者
使用@EventListener注解
如果需要异步的话,加上@Async注解
示例
@Slf4j
@Component
public class DemoEventListener {
@EventListener
public void onApplicationEvent(DemoEvent demoEvent) {
log.info(">>>>>>>>>DemoListener2>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
log.info("收到了:" + demoEvent.getSource() + "消息;时间:" + demoEvent.getTimestamp());
log.info("消息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
}
}
- 测试
@Autowired
private DemoEventPublisher demoEventPublisher;
@Test
public void testEventLister() {
log.info("开始生产消息:==========");
demoEventPublisher.publish(1L, "hello");
}