监听器模式:监听事件的触发,然后做出相应的操作。
当系统运行某些关键节点的时候,会通过广播器去发布一些事件,而系统中存在着一些监听器。对某些事件感兴趣,去订阅这些事件。当这些事件被发布出去之后,监听器监听到这些事件,会触发一些行为。
Spring中的监听器实现
事件(Event):即监听什么。如任务即将执行、任务执行完毕
监听器(Listener):谁来监听
广播器(Multicaster):发布事件、添加/移除监听器
事件触发机制:事件什么时候发布
源码:
1、事件Event
在Spring最顶层的是EventObject类,它代表的是一个事件对象;抽象类ApplicationEvent继承自EventObject,表示的是一个应用事件
EventObject:
public class EventObject implements java.io.Serializable { private static final long serialVersionUID = 5516075349620653480L; protected transient Object source; public EventObject(Object source) { if (source == null) throw new IllegalArgumentException("null source"); this.source = source; } }
ApplicationEvent:
public abstract class ApplicationEvent extends EventObject { /** System time when the event happened. */ private final long timestamp; /** * Create a new ApplicationEvent. * @param source the object on which the event initially occurred (never {@code null}) */ public ApplicationEvent(Object source) { super(source); this.timestamp = System.currentTimeMillis(); } }
2、监听器
ApplicationListener继承自EventListener,EventListener 是一个空接口,用来声明这是一个事件监听的接口。
ApplicationListener:
@FunctionalInterface public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event); // 监听到事件发生的时候,去做一些事情 }
ApplicationListener的泛型继承自ApplicationEvent,因此在实现这个接口的时候,可以声明自己监听的具体事件。
系统在触发这个系统监听器的时候会根据其监听的事件做一个过滤。
3、广播器
系统广播器是 ApplicationEventMulticaster ,实现这个接口来管理一些应用监听器,并且广播事件。
其中定义了添加、删除监听器以及广播事件的方法。
ApplicationEventMulticaster :
public interface ApplicationEventMulticaster { /** * Add a listener to be notified of all events. * @param listener the listener to add */ void addApplicationListener(ApplicationListener<?> listener); /** * Add a listener bean to be notified of all events. * @param listenerBeanName the name of the listener bean to add */ void addApplicationListenerBean(String listenerBeanName); /** * Remove a listener from the notification list. * @param listener the listener to remove */ void removeApplicationListener(ApplicationListener<?> listener); /** * Remove a listener bean from the notification list. * @param listenerBeanName the name of the listener bean to add */ void removeApplicationListenerBean(String listenerBeanName); /** * Remove all listeners registered with this multicaster. * <p>After a remove call, the multicaster will perform no action * on event notification until new listeners are being registered. */ void removeAllListeners(); /** * Multicast the given application event to appropriate listeners. * <p>Consider using {@link #multicastEvent(ApplicationEvent, ResolvableType)} * if possible as it provides a better support for generics-based events. * @param event the event to multicast */ void multicastEvent(ApplicationEvent event); /** * Multicast the given application event to appropriate listeners. * <p>If the {@code eventType} is {@code null}, a default type is built * based on the {@code event} instance. * @param event the event to multicast * @param eventType the type of event (can be null) * @since 4.2 */ void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType); }
4、ApplicationListener监听器注册到Spring容器
1)启动类:
public static void main(String[] args) { SpringApplication.run(CppApplication.class, args); }
2)调用run方法会先创建SpringApplication对象然后调用其run方法;SpringApplication#run 1258
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); } // SpringApplication 构造方法 public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 将监听器对应添加到 private List<ApplicationListener<?>> listeners 中 this.mainApplicationClass = deduceMainApplicationClass(); }
getSpringFactoriesInstances 方法获取到所有ApplicationListener的实现,并创建对象,然后排序。
setListeners 方法:
public void setListeners(Collection<? extends ApplicationListener<?>> listeners) { this.listeners = new ArrayList<>(); // 先初始化SpringApplication的 private List<ApplicationListener<?>> listeners; 属性 this.listeners.addAll(listeners); // 将getSpringFactoriesInstances返回的对象集合添加进去 }
5、广播器初始化并添加监听器到广播器中
1)广播器初始化
AbstractApplicationContext#refresh#initApplicationEventMulticaster() 537行
2)添加监听器到广播器中
AbstractApplicationContext#refresh#registerListeners() 543行
6、事件触发机制
SpringApplication#run 295
301行:获取到所有实现 SpringApplicationRunListener 接口的监听器, 创建对象并添加到SpringApplicationRunListeners类的 List<SpringApplicationRunListener> listeners 属性中。
SpringApplicationRunListener接口中定义了Spring容器启动过程中各个阶段的事件,比如starting、environmentPrepared、contextPrepared、contextLoaded、started、running、failed。
所以只用调用不同的方法就可以在相应的节点触发对应的事件。
比如:SpringApplicationRunListeners#statrting() ,遍历所有的SpringApplicationRunListener类型的监听器并调用其 starting() 方法
又比如 SpringApplicationRunListener 接口的实现类 EventPublishingRunListener 的 starting() 实现:
调用广播器的 multicastEvent 方法发送一个相应的 ApplicationStartingEvent 事件。
multicastEvent() 方法的内部实现:
@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); // 调用监听器的onApplicationEvent()方法,触发事件 } } }
那么,getApplicationListeners() 方法是如何获取对指定时间监听的监听器的?
大致就是判断监听器的泛型的类型,是否与发布事件的类型一致,如果一致将监听器的对象放到一个集合中。
模拟Spring自实现监听器
1、事件 抽象类Event,其他要监控的事件继承它
/** * 事件 * * @author yangyongjie * @date 2020/9/30 * @desc */ public abstract class Event<T> { /** * 事件自身资源 */ protected T source; /** * 事件发生时间 */ private final long timestamp; public Event(T source) { this.source = source; this.timestamp = System.currentTimeMillis(); } public T getSource() { return source; } public void setSource(T source) { this.source = source; } public long getTimestamp() { return timestamp; } }
如:流程结束事件
/** * 审批流程结束事件 * * @author yangyongjie * @date 2020/10/15 * @desc */ public class AuditFlowFinishEvent extends Event<AuditFlow> { public AuditFlowFinishEvent(AuditFlow auditFlow) { super(auditFlow); } }
2、监听器接口 Listener,自定义监听器实现它;泛型表示要监听的事件
/** * 监听器 * * @author yangyongjie * @date 2020/9/30 * @desc */ public interface Listener<E extends Event> { /** * 当事件发生做一些事情 * * @param event */ void onEvent(E event); }
如:审核流程结束监听器
/** * 审核流程结束监听器 * * @author yangyongjie * @date 2020/10/15 * @desc */ @Component public class AuditFlowFinishListener implements Listener<AuditFlowFinishEvent> { private static final Logger LOGGER = LoggerFactory.getLogger(AuditFlowFinishListener.class); @Override public void onEvent(AuditFlowFinishEvent event) { AuditFlow auditFlow = event.getSource(); LOGGER.info("流程结束监听器工作了!"); } }
3、广播器,管理监听器,发布事件
广播器接口:
/** * 事件广播器 * * @author yangyongjie * @date 2020/9/30 * @desc */ public interface EventMulticaster { /** * 添加监听器 * * @param listener */ void addListener(Listener<?> listener); /** * 移除监听器 * * @param listener */ void removeListener(Listener<?> listener); /** * 发布事件 * * @param event */ void multicastEvent(Event event); }
广播器实现类:
/** * 广播器(事件发布器) * * @author yangyongjie * @date 2020/10/15 * @desc */ @Component public class SimpleEventMulticaster implements EventMulticaster, ApplicationContextAware { private static final Logger LOGGER = LoggerFactory.getLogger(SimpleEventMulticaster.class); private final Set<Listener<?>> listeners = new LinkedHashSet<>(); /** * 创建一个执行监听器线程池,核心线程数为1,最大线程数为5,线程空闲时间为60s,拒绝策略为打印日志并直接执行被拒绝的任务 */ private static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(1, 5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(50), new CustomThreadFactory("simpleEventMulticaster"), (r, executor) -> { LOGGER.error("Task:{},rejected from:{}", r.toString(), executor.toString()); // 直接执行被拒绝的任务,JVM另起线程执行 r.run(); }); @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { // 获取容器中实现Listener接口的监听器,并添加到listeners缓存中 Map<String, Listener> listenerMap = applicationContext.getBeansOfType(Listener.class); for (Map.Entry<String, Listener> entry : listenerMap.entrySet()) { addListener(entry.getValue()); } } @Override public void addListener(Listener<?> listener) { this.listeners.add(listener); } @Override public void removeListener(Listener<?> listener) { this.listeners.remove(listener); } @Override public void multicastEvent(Event event) { Class eventClass = event.getClass(); Set<Listener> interestedListeners = getInterestedListeners(eventClass); // 事件发生,异步调用监听器的事件处理方法 for (Listener listener : interestedListeners) { EXECUTOR.execute(() -> listener.onEvent(event)); } } /** * 获取对当前事件感兴趣的监听器 * * @param eventClass */ private Set<Listener> getInterestedListeners(Class eventClass) { // 存放监听对发布事件感兴趣的监听器 Set<Listener> interestedListeners = new LinkedHashSet<>(); for (Listener listener : listeners) { // 获取监听器的泛型类型 ParameterizedType parameterizedType = (ParameterizedType) listener.getClass().getGenericInterfaces()[0]; Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); Listener filterListener = null; for (Type actualTypeArgument : actualTypeArguments) { if (StringUtils.equals(eventClass.getName(), actualTypeArgument.getTypeName())) { filterListener = listener; } } if (filterListener != null) { interestedListeners.add(filterListener); } } return interestedListeners; } }
4、使用广播器发布事件
AuditFlowFinishEvent auditFlowFinishEvent = new AuditFlowFinishEvent(new AuditFlow()); simpleEventMulticaster.multicastEvent(auditFlowFinishEvent);
END.