【Spring】还不赶紧用ApplicationEvent

494 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情

理解使用

想必大家都用过 Spring 的事件处理机制,简单说下,Spring 容器提供各个 Bean 之间的消息通信,往容器发送自定义 Event 事件对象(由 Spring 封装成 PayloadApplicationEvent ),并通知相应的处理该 Event 事件监听器ApplicationListener ,使得Bean之间的依赖关系得到了解耦,便于程序的扩展,同时 Spring 内部实现了容器生命周期的 Event事件 ,对 Spring 集成其他相关组件简直是very友好

1. 自定义ApplicationEvent事件

继承ApplicationEvent或者其子类,编写自定义ApplicationEvent事件

public abstract class SpringApplicationEvent extends ApplicaAtionEvent {
    private final String[] args;

    public SpringApplicationEvent(SpringApplication application, String[] args) {
        super(application);
        this.args = args;
    }

    public SpringApplication getSpringApplication() {
        return (SpringApplication)this.getSource();
    }

    public final String[] getArgs() {
        return this.args;
    }
}

或者使用PayloadApplicationEvent<T>

推荐使用,可以减少相应 ApplicationEvent 子类的定义

在第三步使用 publishEvent 时,可以直接 publish 一个任意 Object,Spring内部会判断是否为ApplicationEvent对象,如果不是则会帮忙封装成一个 PayloadApplicationEvent

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    Assert.notNull(event, "Event must not be null");
    Object applicationEvent;
    if (event instanceof ApplicationEvent) {
        applicationEvent = (ApplicationEvent)event;
    } else {
        // 当publish的对象不是ApplicationEvent以及子类时,由Spring自行封装成PayloadApplicationEvent
        applicationEvent = new PayloadApplicationEvent(this, event);
        if (eventType == null) {
            eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
        }
    }
    ...
    ...
 }

2. 自定义ApplicationListener监听器

编写自定义监听器

private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
   @Override
   public void onApplicationEvent(ContextRefreshedEvent event) {
      FrameworkServlet.this.onApplicationEvent(event);
   }
}

注解方式@EventListener

推荐使用,减少 ApplicationListener 子类的编写,使用注解提高开发效率

@Slf4j
@Component
public class CustomerEventListener {
    
    @EventListener
    public void xxnEventListener(PayloadApplicationEvent<User> event) {
        // your code
    }
}

对于PayloadApplicationEvent,ApplicationListener提供静态方法构造对应的监听器

推荐使用

@Bean
public ApplicationListener<PayloadApplicationEvent<User>> customerListener() {
    return ApplicationListener.forPayload((user) -> {
        // your code
    });
}

3. 调用容器的publishEvent

ApplicationContext applicationContext = SpringContextHolder.getApplicationContext();
//自定义事件
applicationContext.publishEvent(new YourEvent(this));
//使用PayloadApplicationEvent<T>
applicationContext.publishEvent(new PayloadApplicationEvent(this, "xxx"));
applicationContext.publishEvent("xxx");

源码解析

不得不说 Spring 将设计模式运用到了极致, Spring事件处理 底层原理即是我们熟悉的 观察者设计模式

观察者:ApplicationListener

被观察者:ApplicaAtionEvent

Spring容器 使用一个 Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>() 存放不同的 观察者ApplicationListener

PS:以下解读基于读者熟悉Spring Bean的生命周期

1. 往容器里注册ApplicationListener

EventListenerMethodProcessor扫描@EventListener的方法,为其生成ApplicationListener并注册

EventListenerMethodProcessor.java

// Bean生命周期的钩子,在单例Bean实例化后执行
@Override
public void afterSingletonsInstantiated() {
    ...
    String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
    for (String beanName : beanNames) {
        ...
        try {
           //主要方法,解析Bean的@EventListener的方法
           processBean(beanName, type);
        }
        catch (Throwable ex) {
           throw new BeanInitializationException("Failed to process @EventListener " +
                 "annotation on bean with name '" + beanName + "'", ex);
        }
        ...
    }
    ...
}


private void processBean(final String beanName, final Class<?> targetType) {
    ...
    // 扫描到Bean的@EventListener的所有方法
    Map<Method, EventListener> annotatedMethods = null;
    try {
       annotatedMethods = MethodIntrospector.selectMethods(targetType,
             (MethodIntrospector.MetadataLookup<EventListener>) method ->
                   AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
    }
    ...
    
    
    ...
    
    // Non-empty set of methods
    ConfigurableApplicationContext context = this.applicationContext;
    Assert.state(context != null, "No ApplicationContext set");
    List<EventListenerFactory> factories = this.eventListenerFactories;
    Assert.state(factories != null, "EventListenerFactory List not initialized");
    // 遍历@EventListener方法
    for (Method method : annotatedMethods.keySet()) {
       // DefaultEventListenerFactory 和 TransactionalEventListenerFactory (不支持@EventListener,支持@TransactionalEventListener)
       for (EventListenerFactory factory : factories) {
          // 调用DefaultEventListenerFactory工厂
          if (factory.supportsMethod(method)) {
             Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
             // 创建了一个ApplicationListene适配器 ApplicationListenerMethodAdapter
             ApplicationListener<?> applicationListener =
                   factory.createApplicationListener(beanName, targetType, methodToUse);
             if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
             }
             // 注册到容器里
             context.addApplicationListener(applicationListener);
             break;
          }
       }
    }
    ...
}

在Bean初始化后,扫描ApplicationListener类型的Bean注册到容器


ApplicationListenerDetector.java

// Bean生命周期的钩子,在单例Bean初始化化执行
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
   // 遍历扫描ApplicationListener类型的Bean
   if (bean instanceof ApplicationListener) {
      Boolean flag = this.singletonNames.get(beanName);
      if (Boolean.TRUE.equals(flag)) {
         this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
      }
      ...
   }
   return bean;
}


2. 发送事件触发

publishEvent往ApplicationEventMulticaster广播器广播事件


AbstractApplicationContext.java

public void publishEvent(Object event) {
    this.publishEvent(event, (ResolvableType)null);
}

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    Assert.notNull(event, "Event must not be null");
    Object applicationEvent;
    
    // 判断是否为ApplicationEvent,否则包装成PayloadApplicationEvent
    if (event instanceof ApplicationEvent) {
        applicationEvent = (ApplicationEvent)event;
    } else {
        applicationEvent = new PayloadApplicationEvent(this, event);
        if (eventType == null) {
            eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
        }
    }

    if (this.earlyApplicationEvents != null) {
        this.earlyApplicationEvents.add(applicationEvent);
    } else {
       // 使用事件广播器 广播事件
       this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);
    }

    // 如有父容器,向父容器发送事件
    if (this.parent != null) {
        if (this.parent instanceof AbstractApplicationContext) {
            ((AbstractApplicationContext)this.parent).publishEvent(event, eventType);
        } else {
            this.parent.publishEvent(event);
        }
    }

}

默认的ApplicationEventMulticaster广播器找到匹配的事件监听器,并执行监听器的onApplicationEvent


// 默认的事件广播器,可自己扩展注入容器里面
SimpleApplicationEventMulticaster.java


public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
    Executor executor = this.getTaskExecutor();
    // 找到监听该事件的监听器
    Iterator var5 = this.getApplicationListeners(event, type).iterator();

    // 调用监听器的逻辑
    while(var5.hasNext()) {
        ApplicationListener<?> listener = (ApplicationListener)var5.next();
        if (executor != null) {
            // 使用线程池去执行监听器的逻辑, 默认是没有
            executor.execute(() -> {
                this.invokeListener(listener, event);
            });
        } else {
            this.invokeListener(listener, event);
        }
    }

}


protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
    ErrorHandler errorHandler = this.getErrorHandler();
    if (errorHandler != null) {
        try {
            // 直接调用listener的onApplicationEvent方法
            this.doInvokeListener(listener, event);
        } catch (Throwable var5) {
            errorHandler.handleError(var5);
        }
    } else {
        this.doInvokeListener(listener, event);
    }

}