最近公司在重构广告系统, 其中核心的打包功由广告系统调用, 即对 apk 打包的调用和打包完成之后的回调, 需要提供相应的接口给广告系统. 因此, 为了将 apk 打包的核心流程和对接广告系统的业务解耦, 利用了 spring 的事件监听特性来满足需求. 以下说明 spring 的事件机制的相关内容.
1. 观察者模式
Spring 的事件监听 (也称事件驱动) 是观察者模式的一种实现, 比较常见的有发布 - 订阅模型. 通常我们利用消息队列来实现不同系统之间的解耦, 如用户注册完成后, 可以向消息队列发布一条消息, 然后订阅了此 topic 的子系统 (如邮件服务, 积分服务) 收到发布的消息之后, 就会做相应的处理. 这样做的好处是避免了在注册服务里耦合其他服务的代码, 并且, 执行子系统的业务将会异步执行, 互不影响. 下图是一个经典的观察者模式的结构.
以下为上述观察者模式的 java 简单实现:
- (1)Subject.java
- package observerPattern;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * Created by jy on 2018/11/28.
- */
- public abstract class Subject {
- // 维护一个所有观察者集合
- private List<Observer> list = new ArrayList<>();
- // 新注册一个观察者
- public void attach(Observer observer){
- list.add(observer);
- System.out.println("新注册一个观察者");
- }
- // 删除一个已注册的观察者
- public void detach(Observer observer){
- list.remove(observer);
- System.out.println("删除一个已注册的观察者");
- }
- // 通知所有已经注册的观察者
- public void notifyObservers(String state){
- for (int i = 0; i <list.size(); i++) {
- list.get(i).update(state);
- }
- }
- }
- (2)Observer.java
- package observerPattern;
- /**
- * Created by jy on 2018/11/28.
- */
- public interface Observer {
- // 抽象出的更新行为
- public void update(String state);
- }
- (3)ConcreteSubject.java
- package observerPattern;
- /**
- * Created by jy on 2018/11/28.
- */
- public class ConcreteSubject extends Subject{
- // 真实主题内维护一个状态
- private String state;
- public String getState() {
- return state;
- }
- public void change(String state){
- this.state = state;
- System.out.println("真实主题状态变化为:"+state);
- this.notifyObservers(state);
- }
- }
- (4)ConcreteObserver.java
- package observerPattern;
- /**
- * Created by jy on 2018/11/28.
- */
- public class ConcreteObserver implements Observer {
- // 具体观察者的状态
- private String observerState;
- @Override
- public void update(String state) {
- // 这里可以根据传递过来的主题的状态作出相应的业务
- observerState = state;
- System.out.println("观察者的状态跟着变化为:"+observerState);
- }
- }
- (5)Main.java
- package observerPattern;
- /**
- * Created by jy on 2018/11/28.
- */
- public class Main {
- public static void main(String[] args) {
- // 真实主题
- ConcreteSubject concreteSubject = new ConcreteSubject();
- // 真实观察者
- ConcreteObserver concreteObserver = new ConcreteObserver();
- // 观察者先注册
- concreteSubject.attach(concreteObserver);
- // 改变真实主题状态
- concreteSubject.change("2");
- }
- }
结果: 在执行了 main 方法之后, 我们可以看到控制台输出结果, 表明, 真实观察者的状态是会根据真实主题的状态变化而变化的:
2. Spring 事件监听
spring 也对事件驱动模型提供了支持, 该模型主要由三部分组成:
(1) 事件(ApplicationEvent): 继承了 jdk 的 EventObject, 在 spring 项目中可以继承 ApplicationEvent, 来自定义自己的事件.
spring 容器内部对 ApplicationEvent 有着下面几个实现, 通过名字可以很清楚事件所描述的行为.
(2)发布者(ApplicationEventPublisher): 实现这个接口, 就可以使得 spring 组件有发布事件的能力.
可以看到, ApplicationContext 实现了此接口, 因此, 可以 spring 组件可以通过实现 ApplicationContextAware 接口, 注入 ApplicationContext, 然后, 通过 ApplicationContext 的 publishEvent()方法来实现事件传播,
当然, 也可以直接实现 ApplicationEventPublisher 接口, 重写 publishEvent()方法, 同样可以实现事件传播.
通过阅读源码发现, 在 AbstractApplicationContext 类中, 定义了针对观察者的增加, get, 注册等方法:
- @Override
- public void addApplicationListener(ApplicationListener<?> listener) {
- Assert.notNull(listener, "ApplicationListener must not be null");
- //listener 传入持有的一个的 applicationEventMulticaster 类中
- if (this.applicationEventMulticaster != null) {
- this.applicationEventMulticaster.addApplicationListener(listener);
- }
- this.applicationListeners.add(listener);
- }
- // 省略部分代码
- protected void registerListeners() {
- // Register statically specified listeners first.
- for (ApplicationListener<?> listener : getApplicationListeners()) {
- getApplicationEventMulticaster().addApplicationListener(listener);
- }
- // Do not initialize FactoryBeans here: We need to leave all regular beans
- // uninitialized to let post-processors apply to them!
- String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
- for (String listenerBeanName : listenerBeanNames) {
- getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
- }
- // Publish early application events now that we finally have a multicaster...
- Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
- this.earlyApplicationEvents = null;
- if (earlyEventsToProcess != null) {
- for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
- getApplicationEventMulticaster().multicastEvent(earlyEvent);
- }
- }
- }
在 AbstractApplicationContext 中 publishEvent:
- 1 protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
- 2 //.....
- 3 // Multicast right now if possible - or lazily once the multicaster is initialized
- 4 if (this.earlyApplicationEvents != null) {
- 5 this.earlyApplicationEvents.add(applicationEvent);
- 6 }
- 7 else {
- 8 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); // 事件广播
- 10 //....
- 11 }
上面代码中的观察者最终都添加至一个 ApplicationEventMulticaster 类型的类中, 具体的发布事件的方法都在这个类中去实现的, 在 AbstractApplicationContext 中, 会先尝试从 ConfigurableListableBeanFactory 中去加载这个类, 如果不存在, 则会默认 new 一个 SimpleApplicationEventMulticaster:
- protected void initApplicationEventMulticaster() {
- ConfigurableListableBeanFactory beanFactory = getBeanFactory();
- if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { // 尝试加载
- this.applicationEventMulticaster =
- beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
- if (logger.isTraceEnabled()) {
- logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
- }
- }
- else {
- this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); // 不存在则默认使用 SimpleApplicationEventMulticaster
- beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
看看 SimpleApplicationEventMulticaster 是怎么广播事件的, 由代码可知, 在线程池不为空的情况下, 异步发布特定类型的事件.
- @Override
- public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
- ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
- for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
- Executor executor = getTaskExecutor();
- if (executor != null) {
- executor.execute(() -> invokeListener(listener, event));
- }
- else {
- invokeListener(listener, event);
- }
- }
- //....
将 invokeListener 方法点击到最后, 发现调用了 listener 的 onApplicationEvent(), 实现了事件的发布.
- private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
- try {
- listener.onApplicationEvent(event);
- }
- catch (ClassCastException ex) {
- //....
- }
- }
(3)事件订阅者(ApplicationListener): 实现这个接口, 就可以监听 ApplicationListener 发布的特定的事件.
实现 ApplicationListener 这个接口, 重写 onApplicationEvent()方法, 来处理监听到的 ApplicationEvent, 这里可以监听特定类型的事件.
3. 基于注解的事件监听
spring 也为发布者和监听者提供了相应的注解支持, 只需要在对应的观察者类的对应方法上加上 @EventListener:
对于发布者, 可以直接在 service 通过 @Autowired 注入 ApplicationEventPublisher.
4. 小结
文章主要介绍了 spring 中事件驱动的模型. 主要运用了观察者模式的思想, 随后介绍了 spring 中事件发布的机制.
来源: https://www.cnblogs.com/jy107600/p/10034857.html