继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Spring 事件机制

CoderLi_
关注TA
已关注
手记 7
粉丝 2
获赞 2


概念

在一个完整的事件体系中、存在以下的角色

  1. 事件:描述发生了什么事情、比如说请求处理完成、Spring 容器刷新完毕

  2. 事件源:事件的产生者、任何一个事件都必须有一个事件源。比如请求处理完成的事件源就是 DispatcherServlet 、Spring 容器刷新完毕的事件源就是 ApplicationContext

  3. 事件广播器:事件和事件监听器的桥梁、负责把事件通知给事件监听器

  4. 事件监听器:监听事件的发生、可以在监听器中做一些处理

Spring 事件

http://img1.sycdn.imooc.com/61e269130001824a11771080.jpg

我们常见的事件可能就是 ApplicationContextEvent 、它的子类 ContextRefreshedEvent 是我们常见的事件类型、在 Spring 将所有非延迟加载的 bean 实例化之后发布。

http://img4.sycdn.imooc.com/61e269140001a2ff13200706.jpg

再来看看 Spring 事件的体系结构

http://img1.sycdn.imooc.com/61e269140001bc4924100790.jpg

Spring 监听器

http://img2.sycdn.imooc.com/61e269140001af3121960618.jpg


事件广播器

http://img4.sycdn.imooc.com/61e269140001666207200508.jpg

http://img1.sycdn.imooc.com/61e269140001e3ea13711080.jpg

ApplicationContext 对事件的支持

http://img4.sycdn.imooc.com/61e26915000174bc23420556.jpg

ApplicationEventPublisher 这个是 Spring 提供给用户使用的一个事件发布器啊、真正实现发布功能还是委托给上面的 ApplicationEventMulticaster 去实现的。

Spring 提供了 ApplicationEventPublisherAware 让用户可以去获取这个发布器进行事件发布。

使用方式

Spring 提供了两种方式

  1. 实现 ApplicationListener 接口

  2. 使用注解 @EventListener

注解的实现源码

我们直接看到 EventListenerMethodProcessor 该类实现了接口 SmartInitializingSingleton 接口、该接口会在 Spring 初始化完所有的非延迟加载的 bean 之后被调用。

 public interface SmartInitializingSingleton {
 
    /**
     * Invoked right at the end of the singleton pre-instantiation phase,
     * with a guarantee that all regular singleton beans have been created
     * already. {@link ListableBeanFactory#getBeansOfType} calls within
     * this method won't trigger accidental side effects during bootstrap.
     * <p><b>NOTE:</b> This callback won't be triggered for singleton beans
     * lazily initialized on demand after {@link BeanFactory} bootstrap,
     * and not for any other bean scope either. Carefully use it for beans
     * with the intended bootstrap semantics only.
     */
    void afterSingletonsInstantiated();
 }

http://img3.sycdn.imooc.com/61e26915000145ca18981010.jpg

其实实现逻辑非常简单

 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;
       }
    }
 }

找出所有被注解修饰的方法、然后分别创建一个对应的 ApplicationListener、收到事件后反射调用该方法。

 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");
       }
    }
 }

监听器调用的先后顺序

我们可以在 AbstractApplicationEventMulticaster#retrieveApplicationListeners 中看到是支持我们指定监听器的顺序的、Spring 很多涉及顺序的都可以使用

  1. 实现 Ordered 接口

  2. 实现 PriorityOrdered 接口

  3. 使用 @Ordered 接口


异步调用监听器

默认情况下、Spring 创建的事件广播器是采用同步方式调用通知监听器的、我们可以设置或者替换 Spring 默认的监听器来达到异步调用的目的、当然也可以扩展、根据事件的不同采用同步或者异步的方式、而不是单一的要么所有同步要么所有异步

 @Override
 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);
       }
    }
 }

Spring refresh 之前回初始化事件传播器

 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() + "]");
       }
    }
 }

替换原来的事件传播器

 @Component("applicationEventMulticaster")
 public class TestEventMulticaster extends SimpleApplicationEventMulticaster {
 }


           

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP