Java注解@EventListener的神秘面纱

Java注解@EventListener的神秘面纱

前言

最近工作中需要做一个需求,我们系统作为一个中转系统,其他异构系统向我们系统发来付款请求,在我们系统中需要进行付款,但是我们系统是有工作流这个概念的我就在考虑如何监听到我的paymentDto触发判断是否成功付款后工作流执行下一步,并且回调相关的异构系统,那就要介绍我们本期的主角了"事件监听"

简介观察者模式:简单的来讲就是你在做事情的时候身边有人在盯着你,当你做的某一件事情是旁边观察的人感兴趣的事情的时候,他会根据这个事情做一些其他的事,但是盯着你看的人必须要到你这里来登记,否则你无法通知到他(或者说他没有资格来盯着你做事情)。

对于 Spring 容器的一些事件,可以监听并且触发相应的方法。通常的方法有 2 种,ApplicationListener 接口和@EventListener 注解。

要想顺利的创建监听器,并起作用,这个过程中需要这样几个角色:

事件(event)可以封装和传递监听器中要处理的参数,如对象或字符串,并作为监听器中监听的目标。 监听器(listener)具体根据事件发生的业务处理模块,这里可以接收处理事件中封装的对象或字符串。事件发布者(publisher)事件发生的触发者。 @EventListener@EventListener 注解,实现对任意的方法都能监听事件。

在任意方法上标注@EventListener 注解,指定 classes,即需要处理的事件类型,一般就是 ApplicationEven 及其子类,可以设置多项。

代码语言:javascript复制 @Async

@EventListener(paymentCallBackEvent.class)

public void onApplicationEvent(paymentCallBackEvent payArrangeEvent) {

log.info("支付结果已返回");

//TODO:实际业务处理代码

}原理其实上面添加@EventListener注解的方法被包装成了ApplicationListener对象,上面的类似于下面这种写法,这个应该比较好理解。

代码语言:javascript复制@Component

public class MyAnnotationListener implements ApplicationListener {

@Override

public void onApplicationEvent(MyTestEvent event) {

System.out.println("注解监听器1:" + event.getMsg());

}

}那么Spring是什么时候做这件事的呢?

代码语言:javascript复制protected ConfigurableApplicationContext createApplicationContext() {

Class contextClass = this.applicationContextClass;

if (contextClass == null) {

try {

switch (this.webApplicationType) {

case SERVLET:

contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);

break;

case REACTIVE:

contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);

break;

default:

contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);

}

}

catch (ClassNotFoundException ex) {

throw new IllegalStateException(

"Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass",

ex);

}

}

return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);

}他的构造方法如下:

代码语言:javascript复制public AnnotationConfigServletWebServerApplicationContext() {

this.reader = new AnnotatedBeanDefinitionReader(this);

this.scanner = new ClassPathBeanDefinitionScanner(this);

}进到AnnotatedBeanDefinitionReader里面

代码语言:javascript复制public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {

Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

Assert.notNull(environment, "Environment must not be null");

this.registry = registry;

this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);

AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

}再进到AnnotationConfigUtils的方法里面,省略了一部分代码,可以看到他注册了一个EventListenerMethodProcessor类到工厂了。这是一个BeanFactory的后置处理器。

代码语言:javascript复制public static Set registerAnnotationConfigProcessors(

BeanDefinitionRegistry registry, @Nullable Object source) {

DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);

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

}

return beanDefs;

}查看这个BeanFactory的后置处理器EventListenerMethodProcessor,下面方法,他会遍历所有bean,找到其中带有@EventListener的方法,将它包装成ApplicationListenerMethodAdapter,注册到工厂里,这样就成功注册到Spring的监听系统里了。

总结上面介绍了@EventListener的原理,其实上面方法里还有一个@TransactionalEventListener注解,其实原理是一模一样的,只是这个监听者可以选择在事务完成后才会被执行,事务执行失败就不会被执行。

这两个注解的逻辑是一模一样的,并且@TransactionalEventListener本身就被标记有@EventListener,

只是最后生成监听器时所用的工厂不一样而已。

相关文章

济南即将拥有3种共享单车!超全使用攻略收藏备用!

365bet不能提现 09-13

近期违规用户封禁公示

365bet不能提现 07-16

汽车贴膜烤膜方法大全(建议收藏!)

365bet不能提现 09-25

其他物流是什么快递

365beat网址 07-14