1. 快速入门
本文是模拟spring的事件派发机制。
事件类 SendMessageEvent
@ToString
@RequiredArgsConstructor
public class SendMessageEvent extends ApplicationEvent {
private final String from;
private final String to;
private final String content;
}
监听器
写法一:实现 ApplicationListener 接口,并且指定你需要监听的事件类 SendMessageEvent
@Component
@Slf4j
public class SendMessageApplicationListenerV1 implements ApplicationListener<SendMessageEvent> {
@Override
public void onApplicationEvent(SendMessageEvent event) {
log.info("start to send message v1 : {}", event);
}
}
写法二:添加注解 EventListener(SendMessageEvent.class)
@Component
@Slf4j
public class SendMessageApplicationListenerV2 {
@EventListener(SendMessageEvent.class)
public void onApplicationEvent(SendMessageEvent event) {
log.info("start to send message v2 : {}", event);
}
}
使用事件派发器发布事件
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(
Application.class,
args
);
// 获得事件派发器
EventDispatcher dispatcher = ApplicationContextHolder.getBean(EventDispatcher.class);
SendMessageEvent sendMessageEvent = new SendMessageEvent("qyh", "zwd", "this is test Content ");
dispatcher.dispatchEvent(sendMessageEvent);
// c.h.l.t.SendMessageApplicationListenerV1 : start to send message v1 : SendMessageEvent(from=qyh, to=zwd, content=this is test Content )
// c.h.l.t.SendMessageApplicationListenerV2 : start to send message v2 : SendMessageEvent(from=qyh, to=zwd, content=this is test Content )
}
}
2. 核心代码讲解
EventDispatcher 是事件派发器,它实现了 SmartInitializingSingleton 接口,SmartInitializingSingleton 在所有bean都实例化完成之后会回调,EventDispatcher 在回调逻辑里面会遍历spring容器里面的所有bean,收集 实现了 ApplicationListener接口的bean 或者 方法上面添加了 @EventListener 的类,然后通过反射分析它们监听的什么事件。最终形成 map。map的key是事件监听类型,value是 监听此种事件的 监听器集合。发布事件的时候,通过事件类实现了 ApplicationListener接口的bean型定位到 监听器集合,然后循环调用就完事。
注意,这里的bean有两类,一类是 实现了 ApplicationListener接口的bean,一类是方法上面添加了注解 EventListener,他们的处理方式是不同的。对于实现接口的bean,是直接添加到对应监听事件的监听器集合中,对于实现了注解的bean,是为其创建一个监听器适配器 ApplicationListenerAdapter ,适配器实现 ApplicationListener 接口,适配器里面的消费逻辑是通过反射调用目标方法。(这也是设计模式适配器模式的运用)
事件派发器 EventDispatcher
/**
* 事件派发器
*/
@Component
public class EventDispatcher implements SmartInitializingSingleton {
@SuppressWarnings("all")
public final Map<Class<?>, List<ApplicationListener>> ALL_LISTENERS = new HashMap<>();
@SuppressWarnings("all")
public void dispatchEvent(ApplicationEvent event) {
ALL_LISTENERS.getOrDefault(event.getClass(), Collections.emptyList())
.forEach(listener -> listener.onApplicationEvent(event));
}
@Override
public void afterSingletonsInstantiated() {
handleClass();
handleMethod();
}
@SuppressWarnings("all")
private void handleClass() {
Collection<ApplicationListener> applicationListeners = ApplicationContextHolder
.getBeansOfType(ApplicationListener.class).values();
for (ApplicationListener<?> listener : applicationListeners) {
ResolvableType rt = ResolvableType.forClass(listener.getClass());
ResolvableType lisenerType = rt.as(ApplicationListener.class);
if (lisenerType != ResolvableType.NONE) {
// 泛型已经实例化
Class<?> eventType = lisenerType.getGeneric(0).getRawClass();
ALL_LISTENERS.putIfAbsent(eventType, new ArrayList<>());
ALL_LISTENERS.get(eventType).add(listener);
}
}
}
@SuppressWarnings("all")
private void handleMethod() {
Collection<Object> allBean = ApplicationContextHolder
.getBeansOfType(Object.class).values();
for (Object bean : allBean) {
Class<?> clazz = bean.getClass();
ReflectionUtils.doWithMethods(clazz, method -> {
EventListener eventListener = null;
if ((eventListener = findAnnotation(method, EventListener.class)) != null) {
Class<? extends ApplicationEvent> eventType = eventListener.value();
ALL_LISTENERS.putIfAbsent(eventType, new ArrayList<>());
ALL_LISTENERS.get(eventType).add(new ApplicationListenerAdapter(bean, method, eventType));
}
});
}
}
}
监听器适配器 ApplicationListenerAdapter
public class ApplicationListenerAdapter<T extends ApplicationEvent> implements ApplicationListener<T>{
private final Object bean;
private final Method method;
private final Class<T> eventType;
public ApplicationListenerAdapter(Object bean, Method method, Class<T> eventType) {
this.bean = bean;
this.method = method;
this.eventType = eventType;
this.method.setAccessible(true);
}
@Override
public void onApplicationEvent(T event) {
try {
method.invoke(bean,event);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
3. 一些能够扩展的点
1. 添加异步消费功能:
其实可以看到,EventDispatcher发布事件的时候都是遍历每个事件监听器然后调用。所以其实可以区分哪些方法是需要异步执行,哪些方法是需要同步执行。发布事件的时候优先异步执行异步方法,然后遍历同步方法执行。
@Component
@Slf4j
public class SendMessageApplicationListenerV2 {
@EventListener(SendMessageEvent.class)
@AsyncConsume // 添加注解 标识这个方法需要异步执行
public void onApplicationEvent(SendMessageEvent event) {
log.info("start to send message v2 : {}", event);
}
}
@Component
@Slf4j
@AsyncConsume // 添加注解 标识这个类里面的方法 onApplicationEvent() 需要异步执行
public class SendMessageApplicationListenerV1 implements ApplicationListener<SendMessageEvent> {
@Override
public void onApplicationEvent(SendMessageEvent event) {
log.info("start to send message v1 : {}", event);
}
}
2. 指定 consumeExceptionHandler
如果消费任务失败了怎么办,那么你可以指定任务消费失败后的异常处理类,可以记录一下日志什么的。。。。
@Component
@Slf4j
public class SendMessageApplicationListenerV2 {
@EventListener(SendMessageEvent.class)
// 添加注解 标识这个方法需要异步执行
@AsyncConsume
// 添加注解 如果该方法发生异常 使用 SendMessageEventHandler 来处理,关注的异常类型是 SendMessageEventException
@ConsumeExceptionHandler(handler = SendMessageEventHandler.class, handleException = SendMessageEventException.class) '
public void onApplicationEvent(SendMessageEvent event) {
log.info("start to send message v2 : {}", event);
}
}