小家Spring】从Spring中的(ApplicationEvent)事件驱动机制出发,聊聊【观察者模式】【监听者模式】【发布订阅模式】【消息队列MQ】【EventSourcing】...(中)

简介: 小家Spring】从Spring中的(ApplicationEvent)事件驱动机制出发,聊聊【观察者模式】【监听者模式】【发布订阅模式】【消息队列MQ】【EventSourcing】...(中)

知道了原因,从来都不缺解决方案:


  1. 强制使用CGLIB动态代理机制
  2. 监听器(@EventListener)单独写在一个@Compnent里。当然你可以使用内部类没关系,如下也是ok的,若需要高内聚小姑的话可以这么写:


@Slf4j
@Service
public class HelloServiceImpl implements HelloService {
  ...
  // 这里用private是木有关系的  需要注意的是若你使用内部类,建议务必是static的  否则可能报错如下:
  // Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'helloServiceImpl' is expected to be of type 'com.fsx.service.HelloServiceImpl' but was actually of type 'com.sun.proxy.$Proxy35'
  // 因为static的类初始化不依赖于外部类,而非static得依赖外部类(所以若不是CGLIB代理  一样出问题)
    @Component
    private static class MyListener {
      private ApplicationContext applicationContext;
        @EventListener(classes = ContextRefreshedEvent.class)
        public void applicationContextEvent(ContextRefreshedEvent event) {
            applicationContext = event.getApplicationContext();
        }
    }
  ...
}


Spring事件机制原理分析


事件收集(EventListenerMethodProcessor)


事件的收集前面讲了继承ApplicationListener的收集情况,那么此处就重点说说Spring4.2后提供的关于@EventListener注解的情况,看看Spring是怎么收集到这些方法,然后管理起来的。


一切源于Spring容器启动过程中:AnnotationConfigUtils.registerAnnotationConfigProcessors(context)注册的7大基础组件时,其中有一个是EventListenerMethodProcessor,它就是处理EventListener注解然后把它注册为一个特别的ApplicationListener的处理器。 当然还有一个EventListenerFactory(DefaultEventListenerFactory)

// 它是一个SmartInitializingSingleton,所以他会在preInstantiateSingletons()的最后一步执行~~~
// 并且它还是实现了BeanFactoryPostProcessor,所以它需要实现方法`postProcessBeanFactory`
// @since 4.2
public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware {
  @Nullable
  private ConfigurableApplicationContext applicationContext;
  // 解析注解中的Conditon的
  private final EventExpressionEvaluator evaluator = new EventExpressionEvaluator();
  // 视图 这样set也变成线程安全的了
  private final Set<Class<?>> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<>(64)); 
  // 这个方法是BeanFactoryPostProcessor的方法,它在容器的BeanFactory准备完成后,会执行此后置处理器
  // 它的作用:BeanFactory工厂准备好后,就去找所有的EventListenerFactory  然后保存起来
  // 此处:默认情况下Spring在准备Bean工厂的时候,会给我们注册一个`DefaultEventListenerFactory`,
  //如果你使用了注解驱动的Spring事务如@EnableTransactionManagement,它就会额外再添加一个`TransactionalEventListenerFactory`
  // 他俩的实现都非常的简单,下面会简单的说一下~~~
  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    this.beanFactory = beanFactory;
    Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
    List<EventListenerFactory> factories = new ArrayList<>(beans.values());
    // 会根据@Order进行排序~~~~
    AnnotationAwareOrderComparator.sort(factories);
    this.eventListenerFactories = factories;
  }
  @Override
  public void afterSingletonsInstantiated() {
    // 从容器里获得所有的EventListenerFactory,它是用来后面处理标注了@EventListener方法的工厂(Spring默认放置的是DefaultEventListenerFactory,我们也可以继续放  支持@Order等注解)
    List<EventListenerFactory> factories = getEventListenerFactories();
    ConfigurableApplicationContext context = getApplicationContext();
    // 这里厉害了,用Object.class 是拿出容器里面所有的Bean定义~~~  一个一个的检查
    String[] beanNames = context.getBeanNamesForType(Object.class);
    for (String beanName : beanNames) {
      // 不处理Scope作用域代理的类。 和@Scope类似相关
      if (!ScopedProxyUtils.isScopedTarget(beanName)) {
        Class<?> type = null;
        try {
          // 防止是代理,吧真实的类型拿出来
          type = AutoProxyUtils.determineTargetClass(context.getBeanFactory(), beanName);
        }
        if (type != null) {
          // 对专门的作用域对象进行兼容~~~~(绝大部分都用不着)
          if (ScopedObject.class.isAssignableFrom(type)) {
            ...
          }
          // 真正处理这个Bean里面的方法们。。。
          processBean(factories, beanName, type);
        }
      }
    }
  }
  protected void processBean(final List<EventListenerFactory> factories, final String beanName, final Class<?> targetType) {
    // 缓存下没有被注解过的Class,这样再次解析此Class就不用再处理了  
    //这是为了加速父子容器的情况  做的特别优化
    if (!this.nonAnnotatedClasses.contains(targetType)) {
      Map<Method, EventListener> annotatedMethods = null;
      try {
        // 这可以说是核心方法,就是找到这个Class里面被标注此注解的Methods们
        // 在讲述到反射专题的时候,这个方法已经分析过~
        annotatedMethods = MethodIntrospector.selectMethods(targetType,
            (MethodIntrospector.MetadataLookup<EventListener>) method ->
                AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
      }
      catch (Throwable ex) {
        // An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
        if (logger.isDebugEnabled()) {
          logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
        }
      }
      // 若一个都没找到,那就标注此类没有标注注解,那就标记一下此类  然后拉到算了  输出一句trace日志足矣
      if (CollectionUtils.isEmpty(annotatedMethods)) {
        this.nonAnnotatedClasses.add(targetType);
        if (logger.isTraceEnabled()) {
          logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
        }
      }
      //若存在对应的@EventListener标注的方法,那就走这里
      // 最终此Method是交给`EventListenerFactory`这个工厂,适配成一个ApplicationListener的
      // 适配类为ApplicationListenerMethodAdapter,它也是个ApplicationListener
      else {
        // Non-empty set of methods
        ConfigurableApplicationContext context = getApplicationContext();
        // 处理这些带有@EventListener注解的方法们
        for (Method method : annotatedMethods.keySet()) {
          // 这里面注意:拿到每个EventListenerFactory (一般情况下只有DefaultEventListenerFactory,但是若是注解驱动的事务还会有它:TransactionalEventListenerFactory)
          for (EventListenerFactory factory : factories) {
            // 加工的工厂类也可能有多个,但默认只有Spring注册给我们的一个
            // supportsMethod表示是否支持去处理此方法(因为我们可以定义处理器,只处理指定的Method都是欧克的)  Spring默认实现永远返回true(事务相关的除外,请注意工厂的顺序)
            if (factory.supportsMethod(method)) {
              // 简单的说,就是把这个方法弄成一个可以执行的方法(主要和访问权限有关)
              // 这里注意:若你是JDK的代理类,请不要在实现类里书写@EventListener注解的监听器,否则会报错的。(CGLIB代理的木关系) 原因上面已经说明了
              Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
              // 把这个方法包装成一个监听器ApplicationListener(ApplicationListenerMethodAdapter类型)
              // 通过工厂创建出来的监听器  也给添加进context里面去~~~~~
              ApplicationListener<?> applicationListener = factory.createApplicationListener(beanName, targetType, methodToUse);
              if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                // 这个init方法是把ApplicationContext注入进去
                ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
              }
              // 添加进去  管理起来
              context.addApplicationListener(applicationListener);
              // 这个break意思是:只要有一个工厂处理了这个方法,接下来的工厂就不需要再处理此方法了~~~~(所以工厂之间的排序也比较重要)
              break;
            }
          }
        }
      }
    }
  }
}


就着这样,最终我们所有的Listener都被管理了起来。


EventListenerFactory:为Method生产ApplicationListener


它是一个策略结果,准们为Method生产ApplicationListener,类似一个转换器的作用。


// @since 4.2
// Strategy interface for creating {@link ApplicationListener} for methods annotated with {@link EventListener}.
public interface EventListenerFactory {
  // 是否支持此方法 支持才create
  boolean supportsMethod(Method method);
  // 根据Method等相关信息,生成一个ApplicationListener
  ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method);
}


它的实现类常见的有两个:DefaultEventListenerFactoryTransactionalEventListenerFactory

DefaultEventListenerFactory

它是在Bean工厂准备好后,默认都会注册的6大Bean之一~~~~~


public class DefaultEventListenerFactory implements EventListenerFactory, Ordered {
  // 它希望自己是被最后执行的~~~
  private int order = LOWEST_PRECEDENCE;
  public void setOrder(int order) {
    this.order = order;
  }
  @Override
  public int getOrder() {
    return this.order;
  }
  // 匹配所有的标注了@EventListener 的方法
  public boolean supportsMethod(Method method) {
    return true;
  }
  // ApplicationListenerMethodAdapter是一个通用的方法监听适配器~~~~
  @Override
  public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
    return new ApplicationListenerMethodAdapter(beanName, type, method);
  }
}

TransactionalEventListenerFactory


它是一个和注解驱动的声明式事务相关的监听器工厂。用于处理@TransactionalEventListener这个注解标注的方法


public class TransactionalEventListenerFactory implements EventListenerFactory, Ordered {
  private int order = 50;
  public void setOrder(int order) {
    this.order = order;
  }
  @Override
  public int getOrder() {
    return this.order;
  }
  // 很显然,它要求此方法必须标注@TransactionalEventListener这个注解
  // 备注:@TransactionalEventListener继承自@EventListener
  @Override
  public boolean supportsMethod(Method method) {
    return AnnotatedElementUtils.hasAnnotation(method, TransactionalEventListener.class);
  }
  // ApplicationListenerMethodTransactionalAdapter这个是适配事务监听方法的适配器
  // 它继承自:ApplicationListenerMethodAdapter
  @Override
  public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
    return new ApplicationListenerMethodTransactionalAdapter(beanName, type, method);
  }
}


关于@EventListener中condition使用

我们先看@EventListener注解本身的定义:


// @since 4.2 只能标注在方法上  和当作元注解使用
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EventListener {
  @AliasFor("classes")
  Class<?>[] value() default {};
  // 标注此方法需要处理的事件类型~~~
  @AliasFor("value")
  Class<?>[] classes() default {};
  /// 则个条件大多数使用者都非常的默认,毕竟绝大多数情况下都是不需要使用的~~~
  // 总体上,它是根据条件,判断此handler是否需要处理这事件  更加细粒度的控制  支持SpEL表达值
  // 内置的#root.event表示当前事件,#root.args当前方法的入参(数组形式)
  String condition() default "";
}


秉着知其然,知其所以然的态度,下面看看condition条件的生效时机。

首先当然是ApplicationListenerMethodAdapter:


// @since 4.2  @EventListener最终都会适配成它
// GenericApplicationListener接口提供方法:boolean supportsEventType(ResolvableType eventType);
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {
  // 事件表达式处理器  默认使用的SpEL去解析  只是对它进行了增强
  @Nullable
  private EventExpressionEvaluator evaluator;
  public ApplicationListenerMethodAdapter(String beanName, Class<?> targetClass, Method method) {
    this.beanName = beanName;
    this.method = BridgeMethodResolver.findBridgedMethod(method);
    this.targetMethod = (!Proxy.isProxyClass(targetClass) ? AopUtils.getMostSpecificMethod(method, targetClass) : this.method);
    this.methodKey = new AnnotatedElementKey(this.targetMethod, targetClass);
    // 处理@EventListener注解信息  备注:至少指定一个监听类型
    EventListener ann = AnnotatedElementUtils.findMergedAnnotation(this.targetMethod, EventListener.class);
    // 按照上例 此处为org.springframework.context.event.ContextRefreshedEvent
    this.declaredEventTypes = resolveDeclaredEventTypes(method, ann);
    // 拿到条件信息  SpEL中有用
    this.condition = (ann != null ? ann.condition() : null);
    // 从此处也能看出,它是支持在方法上标注@Order来控制执行顺序的
    this.order = resolveOrder(this.targetMethod);
  }
  // 判断该处理器  是否支持当前类型的事件
  // 判断思路很简单:类型匹配上了 就表示可以处理这个事件(支持事件的泛型依赖匹配~~~)
  // 关于condition 是在process处理的时候会生效的
  @Override
  public boolean supportsEventType(ResolvableType eventType) {
    for (ResolvableType declaredEventType : this.declaredEventTypes) {
      if (declaredEventType.isAssignableFrom(eventType)) {
        return true;
      }
      if (PayloadApplicationEvent.class.isAssignableFrom(eventType.toClass())) {
        ResolvableType payloadType = eventType.as(PayloadApplicationEvent.class).getGeneric();
        if (declaredEventType.isAssignableFrom(payloadType)) {
          return true;
        }
      }
    }
    return eventType.hasUnresolvableGenerics();
  }
  // 开始处理事件~~~  此处会checking if the condition match and handling non-null result
  @Override
  public void onApplicationEvent(ApplicationEvent event) {
    processEvent(event);
  }
  public void processEvent(ApplicationEvent event) {
    // 解析参数,很简单  主要是兼容PayloadApplicationEvent 把事件拿出来  
    // 返回的数组要么为[],总之最多只有一个参数  就是事件本身
    Object[] args = resolveArguments(event);
    //  此处是我们本文的重点,就是解析condition 条件的地方,下面专门讨论,现在继续往下走
    // 总之就是根据事件源、绝大多数情况下args里面装的就是这个event~~~~~
    if (shouldHandle(event, args)) {
      Object result = doInvoke(args); // 这一句非常的简单  就是调用此方法Method~
      // 这一步就是@EventListener最大的优势。如果它的返回值不为null,那么它可以行使事件链,可以继续发布事件  
      // 把返回值当作事件继续publish(返回值可以是个Object,最终被包装成payload事件~~~~)
      if (result != null) {
        handleResult(result);
      } else {
        logger.trace("No result object given - no result to handle");
      }
    }
  }
}


从源码处可知,真正执行的时候,还要经过condition这一关:下面作为本处的重点,重点分析一下此方法:


  private boolean shouldHandle(ApplicationEvent event, @Nullable Object[] args) {
    if (args == null) {
      return false;
    }
    String condition = getCondition();
    // condition默认是空串  只有配置了才会去执行~~~  是用的解析器是EventExpressionEvaluator
    if (StringUtils.hasText(condition)) {
      Assert.notNull(this.evaluator, "EventExpressionEvaluator must not be null");
      // 最终委托给EventExpressionEvaluator去解析
      // 备注EventExpressionEvaluator是个内部使用的类,只有此处解析用到了~~~
      return this.evaluator.condition(condition, event, this.targetMethod, this.methodKey, args, this.applicationContext);
    }
    return true;
  }


EventExpressionEvaluator:表达式执行器


它是处理SpEL表达式解析的实用程序类。用于可重用、线程安全的组件


// @since 4.2   CachedExpressionEvaluator也是4.2出来的,提供了缓存的能力,并且内部使用SpEL来解析表达式~~~
class EventExpressionEvaluator extends CachedExpressionEvaluator {
  // ExpressionKey为CachedExpressionEvaluator的一个吧内部类
  // Expression为:org.springframework.expression.Expression 表达式
  private final Map<ExpressionKey, Expression> conditionCache = new ConcurrentHashMap<>(64);
  // 它只有这个一个方法~~~
  public boolean condition(String conditionExpression, ApplicationEvent event, Method targetMethod,
      AnnotatedElementKey methodKey, Object[] args, @Nullable BeanFactory beanFactory) {
    // EventExpressionRootObject就是简单的持有传入的两个变量的引用而已~~~
    // 这个RootObject是我们#root值的来源~~~~
    EventExpressionRootObject root = new EventExpressionRootObject(event, args);
    // 准备一个执行上下文。关于SpEL的执行上文,请参照下面的链接
    // 这个执行上下文是处理此问题的重中之重~~~~下面会有解释
    // getParameterNameDiscoverer 它能够根据方法参数列表的名称取值~~~强大  
    // 同时也支持a0、a1... 和 p0、p1...等等都直接取值~~这个下面会为何会支持得这么强大的原因~~~
    MethodBasedEvaluationContext evaluationContext = new MethodBasedEvaluationContext(root, targetMethod, args, getParameterNameDiscoverer());
    if (beanFactory != null) {
      evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
    }
    // 可以看到  请让表达式的值返回bool值~~~~~~~
    // getExpression是父类的~  最终有用的就一句话:expr = getParser().parseExpression(expression);
    // 默认采用的是SpelExpressionParser这个解析器解析这个表达式
    return (Boolean.TRUE.equals(getExpression(this.conditionCache, methodKey, conditionExpression).getValue(
        evaluationContext, Boolean.class)));
  }
}

关于SpEL这块,强烈建议先参照:

【小家Spring】SpEL你感兴趣的实现原理浅析spring-expression~(SpelExpressionParser、EvaluationContext、rootObject)

MethodBasedEvaluationContext :执行器的执行上下文


它是个SpEL中的EvaluationContext。这里最重要的是MethodBasedEvaluationContext这个执行上下文,其实也比较简单。比较有意思的一点是它支持取值除了#root.xxx方式,还支持有a0、a1... 和 p0、p1...等方式

// @since 4.2
public class MethodBasedEvaluationContext extends StandardEvaluationContext {
  ...
  private final Object[] arguments;
  private final ParameterNameDiscoverer parameterNameDiscoverer;
  // .... 这里是按照变量名或者a0这种方式取值的核心处理~~~~
  protected void lazyLoadArguments() {
    // 支持根据参数名取值
    String[] paramNames = this.parameterNameDiscoverer.getParameterNames(this.method);
    ...
    // variables是个Map<String, Object> variables
    for (int i = 0; i < paramCount; i++) {
      // 支持a0、a1..方式取值
      setVariable("a" + i, value);
      // 支持p0、p1..方式取值
      setVariable("p" + i, value);
      // 根据参数列表的形参名字进行取值   如id、name或者obj对象都是ok的(如果是对象,也是支持Bean导航的,因为SpEL是支持的)
      if (paramNames != null && paramNames[i] != null) {
        setVariable(paramNames[i], value);
      }
    }
  }
}


处理Event的执行上下文是MethodBasedEvaluationContext,支持cache相关注解使用的上下文是CacheEvaluationContext。

由于CacheEvaluationContext是MethodBasedEvaluationContext的子类,所以我们cache相关注解比如@Cacheable等等,他们使用SpEL时也都是支持使用上面方式取值的~~~~


关于cache注解的表达式执行器请参考:org.springframework.cache.interceptor.CacheOperationExpressionEvaluator


事件发布(SimpleApplicationEventMulticaster)


我们一般都会使用AbstractApplicationContext#publish()来发布一个事件:


  protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    // Decorate event as an ApplicationEvent if necessary
    // 如果这个事件不是ApplicationEvent类型,那就包装成这个类型
    ApplicationEvent applicationEvent;
    if (event instanceof ApplicationEvent) {
      applicationEvent = (ApplicationEvent) event;
    } else {
      // 注意此处:第一个参数为source,这里传的source,第二个是payload,才传的是事件本身
      applicationEvent = new PayloadApplicationEvent<>(this, event);
      // 若没有指定类型。就交给PayloadApplicationEvent<T>,它会根据泛型类型生成出来的~~~
      if (eventType == null) {
        eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
      }
    }
    // Multicast right now if possible - or lazily once the multicaster is initialized
    // 如果是早期事件,就添加进去  会立马发布了(一般都不属于这种)
    if (this.earlyApplicationEvents != null) {
      this.earlyApplicationEvents.add(applicationEvent);
    } else {
      // 最终把这些时间都委派给了`ApplicationEventMulticaster` 让它去发送事件
      getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    }
    // Publish event via parent context as well...
    // 此处注意:特别重要,如果是父容器,也会向父容器里广播一份~~~~~
    if (this.parent != null) {
      // 这个判断的用意是,既然eventType已经解析出来了,所以就调用protected内部方法即可,而不用再次解析一遍了
      if (this.parent instanceof AbstractApplicationContext) {
        ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
      }
      // 如果是普通的发布,就没有eventType了
      else {
        this.parent.publishEvent(event);
      }
    }
  }


最后事件都会向父类里广播一份,这个就特别想js事件冒泡机制


因此重点看看ApplicationEventMulticaster#multicastEvent:它的唯一实现为:


public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
  // 若set了一个执行器,那所有的监听器都将会异步执行
  @Nullable
  private Executor taskExecutor;
  // 监听者执行失败的回调~~~~~~(比如做回滚等等)
  @Nullable
  private ErrorHandler errorHandler;
  @Override
  public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    // 这里面有个细节:如果有执行器executor ,那就会扔给线程池异步去执行
    // 默认情况下是没有的(Spring默认情况下同步执行这些监听器的)  我们可以调用set方法配置一个执行器(建议)
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
      Executor executor = getTaskExecutor();
      // 放在线程池里执行,相当于异步执行。绝大多数情况下,这里都是null
      if (executor != null) {
        executor.execute(() -> invokeListener(listener, event));
      } else {
        invokeListener(listener, event);
      }
    }
  }
}
  private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    try {
      // 如果是实现了ApplicationListener接口,则直接调用其中的onApplicationEvent()方法;
      //如果是用@EventListener注释,则调用ApplicationListenerMethodAdapter中的onApplicationEvent()方法
      listener.onApplicationEvent(event);
    }
  }


ApplicationListenerMethodAdapter#onApplicationEvent


  @Override
  public void onApplicationEvent(ApplicationEvent event) {
    processEvent(event);
  }
  public void processEvent(ApplicationEvent event) {
    // 获取参数,最终会交给回调的方法的。事件类型是PayloadApplicationEvent,那就把.getPayload(),否则就是event本身喽
    Object[] args = resolveArguments(event);
    // 解析condition表达式(注意,此处把args传进去了) 因此我们表达式里是可以用这个参数的哦
    if (shouldHandle(event, args)) {
      // 就是执行目标方法,我们一般返回值都是void,所以就是null
      // 但是,但是,但是注意了,此处若返回的不是null,还有处理~~~~非常给力:
      Object result = doInvoke(args);
      if (result != null) {
        // 如果返回值是数组或者Collection,会把里面内容当作事件循环publishEvent
        // 如果就是个POJO,那就直接publish  
        // 事件的传递性 就这么的来了,强大啊
        handleResult(result);
      }
      else {
        logger.trace("No result object given - no result to handle");
      }
    }
  }


Spring的使用@EventListener监听事件。若监听方法有返回值,那将会把这个返回值当作事件源,一直发送下去,直到返回void或者null停止


    @EventListener(value = {ContextRefreshedEvent.class})
    public List<Child> handle(Object o) {
        List<Child> childList = new ArrayList<>();
        childList.add(new Child("1"));
        childList.add(new Child("2"));
        return childList;
    }
    // 因为上个方法有返回  所以事件会传递到此处
    @EventListener(Child.class)
    public void handChild(Child c) {
        System.out.println(c.getName() + " 发来了事件");
    }
输出:
1 发来了事件
2 发来了事件


Spring事件传递的应用场景,巧妙的使用,可以事半功倍。(当然必须了解原理,才能运用自如)


这里,抽象父类AbstractApplicationEventMulticaster内部的一些方法是不容忽视的:比如getApplicationListeners:获取对应的监听者

相关实践学习
RocketMQ一站式入门使用
从源码编译、部署broker、部署namesrv,使用java客户端首发消息等一站式入门RocketMQ。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
2月前
|
Web App开发 监控 Java
|
3月前
|
消息中间件 Java Maven
一文搞懂Spring Boot整合RocketMQ
一文搞懂Spring Boot整合RocketMQ
110 0
|
3月前
|
消息中间件 存储 监控
搭建消息时光机:深入探究RabbitMQ_recent_history_exchange在Spring Boot中的应用【RabbitMQ实战 二】
搭建消息时光机:深入探究RabbitMQ_recent_history_exchange在Spring Boot中的应用【RabbitMQ实战 二】
34 1
|
3月前
|
消息中间件 监控 Java
Spring Boot中的RabbitMQ死信队列魔法:从异常到延迟,一网打尽【RabbitMQ实战 一】
Spring Boot中的RabbitMQ死信队列魔法:从异常到延迟,一网打尽【RabbitMQ实战 一】
73 0
|
3月前
|
消息中间件 NoSQL Java
Redis Streams在Spring Boot中的应用:构建可靠的消息队列解决方案【redis实战 二】
Redis Streams在Spring Boot中的应用:构建可靠的消息队列解决方案【redis实战 二】
248 1
|
2月前
|
消息中间件 存储 Cloud Native
【Spring云原生系列】Spring RabbitMQ:异步处理机制的基础--消息队列 原理讲解+使用教程
【Spring云原生系列】Spring RabbitMQ:异步处理机制的基础--消息队列 原理讲解+使用教程
|
3月前
|
NoSQL Java Redis
Spring boot 实现监听 Redis key 失效事件
【2月更文挑战第2天】 Spring boot 实现监听 Redis key 失效事件
81 0
|
4月前
|
消息中间件 Java Spring
一文看懂Spring Boot整合Rabbit MQ实现多种模式的生产和消费
一文看懂Spring Boot整合Rabbit MQ实现多种模式的生产和消费
66 0
|
2月前
|
Java 应用服务中间件 Maven
SpringBoot 项目瘦身指南
SpringBoot 项目瘦身指南
46 0

热门文章

最新文章

相关产品

  • 云消息队列 MQ