背景
随着业务越来越复杂,我们的项目开始采用 DDD 的架构方案,其中 DDD 的领域事件采用 Spring Event 实现,实现起来超级简单。
Spring Event 基本用法
Spring Event 的三个基本概念:
- 事件: 定义事件,继承
ApplicationEvent实现一个事件类。 - 事件监听器:监听并处理事件,通过实现
ApplicationListener或是在处理方法上使用@EventListener注解实现。 - 事件发布器:发布事件,使用
ApplicationEventPublisher.publishEvent发布事件。
// 自定义事件
public class TestEvent extends ApplicationEvent {
public TestEvent(Object source) {
super(source);
}
}
// 自定义监听器
@Component
public class TestListener implements ApplicationListener<TestEvent> {
@Override
public void onApplicationEvent(TestEvent event) {
System.out.println(event);
}
}
// 发布事件
public void test() {
ApplicationEventPublisher context = new AnnotationConfigApplicationContext();
context.publishEvent(new TestEvent("发布自定义事件"));
}
原理
事件发布
// AbstractApplicationContext 中实现了事件发布的逻辑
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
// 获取事件派发器,派发事件给所有的监听器
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
}
// 派发事件
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 如果有设置 Executor 则使用 Executor 异步执行,否则同步执行
Executor executor = getTaskExecutor();
// 获取所有的监听器,遍历监听器执行回调
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
// 回调
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
}
}
1、获取事件派发器 getApplicationEventMulticaster()。 事件派发器在容器初始化时创建,后面还会提到。
2、获取 Executor,如果配置了 Executor,则使用 Executor 进行异步回调。
3、获取所有的监听器,遍历监听器,调用 onApplicationEvent() 回调。
获取所有 ApplicationListener 逻辑,在事件派发器中定义了一个内部类 ListenerRetriever用于缓存所有的监听器。
private class ListenerRetriever {
public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
// 缓存 beanName,用于原型模式,每次调用创建新的 bean
public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
}
private Collection<ApplicationListener<?>> retrieveApplicationListeners() {
List<ApplicationListener<?>> allListeners = new ArrayList<>();
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
synchronized (this.retrievalMutex) {
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
// 将所有的 listener 加入返回结果中
for (ApplicationListener<?> listener : listeners) {
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
retriever.applicationListeners.add(listener);
}
allListeners.add(listener);
}
}
if (!listenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
try {
Class<?> listenerType = beanFactory.getType(listenerBeanName);
if (listenerType == null || supportsEvent(listenerType, eventType)) {
// 通过 beanName 和 type 获取 bean 的实例
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
if (beanFactory.isSingleton(listenerBeanName)) {
// 如果是单例模式加入到 retriever.applicationListeners 中
retriever.applicationListeners.add(listener);
}
else {
retriever.applicationListenerBeans.add(listenerBeanName);
}
}
allListeners.add(listener);
}
}
}
catch (NoSuchBeanDefinitionException ex) {
}
}
}
// 通过 order 进行排序
AnnotationAwareOrderComparator.sort(allListeners);
if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
retriever.applicationListeners.clear();
retriever.applicationListeners.addAll(allListeners);
}
return allListeners;
}
1、在派发器的 retriever 中保存了所有的监听器 bean 实例和 beanName。(在容器初始化的时候保存beanName)
2、首先将所有的 bean 实例加入返回列表中,在遍历 beanName 从 BeanFactory 中获取 bean 的实例加入到返回列表中。对于单例模式的 bean 在加入到监听器列表中。
3、通过 @Order 注解排序
初始化事件监听器和事件派发器
// 启动 spring 容器时通过refresh 方法刷新容器
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
// 初始化事件派发器
initApplicationEventMulticaster();
onRefresh();
// 注册监听器
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
}
}
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);
}
else {
// 如果容器中没有则创建 SimpleApplicationEventMulticaster 派发器加入到容器中
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
}
1、初始化派发器的逻辑非常简单,先从容器中获取 beanName 为 applicationEventMulticaster 的 bean 做为派发器,如果没有则创建 SimpleApplicationEventMulticaster 做为派发器。
protected void registerListeners() {
// 首先注册指定监听器
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 获取说有的监听器name,加入到派发器中
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
}
1、注册监听器的逻辑也很简单,获取所有的 ApplicationListener 的 beanName,加入到派发器中。
@EventListener 注解
Spring 中提到注解就离不开 Processor 了,EventListener 注解也不例外,通过 EventListenerMethodProcessor 实现监听器的注册
public class EventListenerMethodProcessor
implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
}
public interface SmartInitializingSingleton {
void afterSingletonsInstantiated();
}
1、EventListenerMethodProcessor 实现了 SmartInitializingSingleton,SmartInitializingSingleton 这个接口在会在 Spring 容器实例化所有的单例对象后进行回调。
public void afterSingletonsInstantiated() {
ConfigurableListableBeanFactory beanFactory = this.beanFactory;
// 获取所有的 beanName
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
Class<?> type = null;
try {
// 获取 bean 的 class 类型
type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
}
if (type != null) {
try {
// 实例化 bean
processBean(beanName, type);
}
}
}
}
private void processBean(final String beanName, final Class<?> targetType) {
if (!this.nonAnnotatedClasses.contains(targetType) &&
!targetType.getName().startsWith("java") &&
!isSpringContainerClass(targetType)) {
Map<Method, EventListener> annotatedMethods = null;
try {
// 反射获取 EventListener 注解的方法
annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method ->
AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
}
if (CollectionUtils.isEmpty(annotatedMethods)) {
this.nonAnnotatedClasses.add(targetType);
}
else {
ConfigurableApplicationContext context = this.applicationContext;
Assert.state(context != null, "No ApplicationContext set");
List<EventListenerFactory> factories = this.eventListenerFactories;
Assert.state(factories != null, "EventListenerFactory List not initialized");
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
// 校验该方法不是 private、不是 static,且是被代理的方法
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
// 创建监听器
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
// 初始化监听器
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
}
context.addApplicationListener(applicationListener);
break;
}
}
}
}
}
}
1、@EventListener 通过 EventListenerMethodProcessor 实现监听器的创建和注册,EventListenerMethodProcessor 实现了 SmartInitializingSingleton 接口,在单例对象实例化后回调。
2、获取容器中所有的 bean 并遍历。
3、获取 bean 中带有 @EventListener 注解的方法。
4、校验方法,不是 private、static,且是被代理的,然后创建监听器并初始化。
5、加入到容器中。
总结
Spring Event 使用起来非常简单,很适合做为领域事件的实现方案。Spring Event 中通过继承 ApplicationEvent 定义一个事件,实现 ApplicationListener 或者使用 @EventListener 注解监听并处理事件,在通过 ApplicationEventPublisher 发布事件。Spring Event 实现原理在 Spring 容器刷新时先初始化派发器,然后注册所有的 ApplicationListener,最后通过 EventListenerMethodProcessor 注册带有 @EventListener 注解的方法。