浅析Spring事件
Spring事件主要有三部分组成,事件发布器、事件、事件监听器。本文将从以上几个方面简要分析一下Spring 事件的实现,Spring在事件上整体逻辑还是比较简单。
1. 如何使用?
Spring事件都有用过,所以就不单独说明如何使用,简单说明一下,本文使用到的例子。
java
@Configuration
public class EventDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(EventDemo.class);
context.refresh();
context.publishEvent("test");
context.publishEvent(new PayloadApplicationEvent<Integer>(context, 12));
context.publishEvent(new PayloadApplicationEvent<Integer>(context, 10));
context.publishEvent(1.1);
context.close();
}
@EventListener
public void test(PayloadApplicationEvent<String> event) {
String payload = event.getPayload();
System.out.println(payload);
}
@EventListener(condition = "#root.args[0].payload == 12")
public void testInteger(PayloadApplicationEvent<Integer> event) {
System.out.println(event.getPayload());
}
@EventListener
public void testDouble(PayloadApplicationEvent<Double> event) {
System.out.println(event.getPayload());
}
}
输出结果为:
bash
test
12
1.1
2. 事件发布器
在ApplicationContext启动的流程中,会主动创建事件发布器。默认情况为SimpleApplicationEventMulticaster,ApplicationContext在此基础上作了封装,实际事件发布或者事件订阅,都是SimpleApplicationEventMulticaster在处理。而SimpleApplicationEventMulticaster也是Spring上唯一的ApplicationEventMulticaster接口实现类。
java
//AbstractApplicationContext#initApplicationEventMulticaster
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);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
事件发布,事件会上调用ApplicationEventMulticaster接口的multicastEvent方法。在SimpleApplicationEventMulticaster上的实现,可以看到,默认可以通过手动设置Executor,来实现异步调用监听器(在Listener不通过@Async注解的情况下)
java
//SimpleApplicationEventMulticaster#multicastEvent
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
默认情况下SimpleApplicationEventMulticaster的Executor为空,需要手动设置。
java
//SimpleApplicationEventMulticaster#getTaskExecutor
protected Executor getTaskExecutor() {
return this.taskExecutor;
}
java
//SimpleApplicationEventMulticaster#setTaskExecutor
public void setTaskExecutor(@Nullable Executor taskExecutor) {
this.taskExecutor = taskExecutor;
}
在调用Listener的时候,可以设置错误处理,单调用出错时,可以做相应逻辑
java
//SimpleApplicationEventMulticaster#invokeListener
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
默认情况下SimpleApplicationEventMulticaster的ErrorHandler为空,需要手动设置。
java
//SimpleApplicationEventMulticaster#getErrorHandler
protected ErrorHandler getErrorHandler() {
return this.errorHandler;
}
java
//SimpleApplicationEventMulticaster#setErrorHandler
public void setErrorHandler(@Nullable ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
在真正调用的时候,会调用ApplicationListener接口的onApplicationEvent方法。
java
//SimpleApplicationEventMulticaster#doInvokeListener
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
}
else {
throw ex;
}
}
}
3. 事件发布
以通过ApplicationContext发布事件为例,
java
//AbstractApplicationContext#publishEvent
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}
内部会调用publishEvent方法,带有ResolvableType。如果发送的时间不是ApplicationEvent类型,则会通过PayloadApplicationEvent进行包装;如果还在启动阶段,则会先加入早期事件列表;如果ApplicationContext还有父类,则父类也会发送事件。
java
//AbstractApplicationContext#publishEvent
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}else {
//不是ApplicationEvent类型,会用PayloadApplicationEvent包装一层
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// 如果还在启动阶段,那么就加入到早期事件
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// 父类Context也会发送事件
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
在获取ApplicationEventMulticaster然后会调用multicastEvent的方法,在前面我们知道,默认的ApplicationEventMulticaster就是SimpleApplicationEventMulticaster。发送的逻辑也比较简单,就是获取跟事件类型匹配的ApplicationListener,匹配将通过事件的类型(匹配逻辑此处不展开),然后(可以异步调用)调用ApplicationListener的onApplicationEvent方法。
java
//SimpleApplicationEventMulticaster#multicastEvent
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
4. 事件订阅
那么ApplicationListener怎么来呢,需要通过事件的订阅,有两种方式处理。
4.1 实现ApplicationListener接口
在ApplicationContext启动的流程中,会添加一个BeanPostProcessor到BeanFactory中。通过BeanPostProcessor扩展接口,处理ApplicationListener接口的注册
java
//AbstractApplicationContext#prepareBeanFactory
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
}
在ApplicationListenerDetector的postProcessAfterInitialization方法,会判断bean是否实习ApplicationListener,并且如果是单例的话,会通过通过ApplicationContext添加ApplicationListener,完成接口的订阅
java
//ApplicationListenerDetector#BeanPostProcessor
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof ApplicationListener) {
// potentially not detected as a listener by getBeanNamesForType retrieval
Boolean flag = this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
// singleton bean (top-level or inner): register on the fly
this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
}
}
return bean;
}
在AbstractApplicationContext内部如果applicationEventMulticaster不为空,则通过applicationEventMulticaster增加监听器,同时也将添加到applicationListeners列表,此目的之一,是为了防止ApplicationEventMulticaster还没有初始化之前就调用了addApplicationListener接口。
java
//AbstractApplicationContext#addApplicationListener
public void addApplicationListener(ApplicationListener<?> listener) {
Assert.notNull(listener, "ApplicationListener must not be null");
if (this.applicationEventMulticaster != null) {
this.applicationEventMulticaster.addApplicationListener(listener);
}
this.applicationListeners.add(listener);
}
因此在Spring 启动流程中,在registerListeners步骤中(在初始化ApplicationEventMulticaster之后),会将applicationListeners列表的监听器,添加到ApplicationEventMulticaster中。
java
//AbstractApplicationContext#registerListeners
protected void registerListeners() {
// Register statically specified listeners first.
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
//...
}
4.2 @EventListener注解
在AnnotatedBeanDefinitionReader对象创建的时候,会注册两个BeanDefinition(作为内部类)到容器中:EventListenerMethodProcessor和DefaultEventListenerFactory
java
//AnnotatedBeanDefinitionReader
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
java
//AnnotationConfigUtils#registerAnnotationConfigProcessors
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
}
在ApplicationContext启动的流程中,在预创建Bean实例的时候,会调用SmartInitializingSingleton的afterSingletonsInstantiated方法
java
public void preInstantiateSingletons() throws BeansException {
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
smartSingleton.afterSingletonsInstantiated();
}
}
}
EventListenerMethodProcessor实现了SmartInitializingSingleton接口,因此@EventListener注解封装成ApplicationListener接口的逻辑,就会在该类中实现。
java
//EventListenerMethodProcessor#afterSingletonsInstantiated
public void afterSingletonsInstantiated() {
//...
processBean(beanName, type);
//...
}
首先会获取方法和EventListener注解的映射关系
java
//EventListenerMethodProcessor#processBean
Map<Method, EventListener> annotatedMethods = null;
try {
annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method ->
AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
}
然后会遍历方法和EventListener,然后会会循环处理EventListenerFactory,而从前面我们得知,一般情况下EventListenerFactory只有,DefaultEventListenerFactory。而DefaultEventListenerFactory的supportsMethod默认都是true,所以会调用DefaultEventListenerFactory的createApplicationListener方法。
java
//EventListenerMethodProcessor#processBean
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
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;
}
}
}
其中默认返回的默认是ApplicationListenerMethodAdapter方法,还会触发init方法调用(判断ApplicationListenerMethodAdapter后调init,感觉有点硬编码),最后会加入到ApplicationContext的事件监听器列表中。
java
//DefaultEventListenerFactory#createApplicationListener
public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
return new ApplicationListenerMethodAdapter(beanName, type, method);
}
ApplicationListenerMethodAdapter的init方法也很简单,就是存储了一下成员变量
java
//ApplicationListenerMethodAdapter#init
void init(ApplicationContext applicationContext, EventExpressionEvaluator evaluator) {
this.applicationContext = applicationContext;
this.evaluator = evaluator;
}
4.3 ApplicationListenerMethodAdapter处理
ApplicationListenerMethodAdapter肯定是实现了ApplicationListener接口的,那么看下onApplicationEvent方法中,如何代理方法操作。
java
//ApplicationListenerMethodAdapter#onApplicationEvent
public void onApplicationEvent(ApplicationEvent event) {
processEvent(event);
}
首先会解析参数,然后判断是否要调用,是的话会执行调用,如果有返回结果则还会处理返回结果。
java
//ApplicationListenerMethodAdapter#processEvent
public void processEvent(ApplicationEvent event) {
Object[] args = resolveArguments(event);
if (shouldHandle(event, args)) {
Object result = doInvoke(args);
if (result != null) {
handleResult(result);
}
else {
logger.trace("No result object given - no result to handle");
}
}
}
1)解析参数,主要是获取参数,以便后面做表达式的判断。这里对于PayloadApplicationEvent的判断有点奇怪,如果事件不是ApplicationEvent的子类但是对象又是PayloadApplicationEvent,我们知道PayloadApplicationEvent是继承了ApplicationEvent,所以这里的判断不知道什么场景下才会使用。
java
//ApplicationListenerMethodAdapter#resolveArguments
protected Object[] resolveArguments(ApplicationEvent event) {
ResolvableType declaredEventType = getResolvableType(event);
if (declaredEventType == null) {
return null;
}
if (this.method.getParameterCount() == 0) {
return new Object[0];
}
Class<?> declaredEventClass = declaredEventType.toClass();
if (!ApplicationEvent.class.isAssignableFrom(declaredEventClass) &&
event instanceof PayloadApplicationEvent) {
Object payload = ((PayloadApplicationEvent) event).getPayload();
if (declaredEventClass.isInstance(payload)) {
return new Object[] {payload};
}
}
return new Object[] {event};
}
2)判断是否能调用,@EventListener注解是可以写condition参数的,里面会调用expression表达式,进行判断。
java
//ApplicationListenerMethodAdapter#shouldHandle
private boolean shouldHandle(ApplicationEvent event, @Nullable Object[] args) {
if (args == null) {
return false;
}
String condition = getCondition();
if (StringUtils.hasText(condition)) {
Assert.notNull(this.evaluator, "EventExpressionEvaluator must not be null");
return this.evaluator.condition(
condition, event, this.targetMethod, this.methodKey, args, this.applicationContext);
}
return true;
}
3)确认需要调用后,会通过反射的方式,调用方法。
java
//ApplicationListenerMethodAdapter#doInvoke
protected Object doInvoke(Object... args) {
Object bean = getTargetBean();
ReflectionUtils.makeAccessible(this.method);
try {
return this.method.invoke(bean, args);
}
}
4)最后会处理接口,如果事件监听器返回了对象,那么会把这个对象再次通过事件发送出去。
java
//ApplicationListenerMethodAdapter#handleResult
protected void handleResult(Object result) {
if (result.getClass().isArray()) {
Object[] events = ObjectUtils.toObjectArray(result);
for (Object event : events) {
publishEvent(event);
}
}
else if (result instanceof Collection<?>) {
Collection<?> events = (Collection<?>) result;
for (Object event : events) {
publishEvent(event);
}
}
else {
publishEvent(result);
}
}
java
//ApplicationListenerMethodAdapter#publishEvent
private void publishEvent(@Nullable Object event) {
if (event != null) {
this.applicationContext.publishEvent(event);
}
}
这个特性不知道用不好可能会出现死循环,例如以下例子,会导致循环发布事件。
发布事件
arduino
context.publishEvent(new PayloadApplicationEvent<String>(this,"111"));
监听事件
java
@EventListener
public String test(PayloadApplicationEvent<String> event){
String payload = event.getPayload();
System.out.println(payload);
return "123456";
}
5. 参考资料
- Spring 5.1.x源码