>

spring中的事件监听机制

一、前言

事件监听机制也是设计模式中观察者模式的一种实现。在spring中主要有实现ApplicationListener 接口和@EventListener 注解两种方式实现。

实现事件监听机制需要以下三个角色:

1、事件(event)可以封装和传递监听器中要处理的参数,如对象或字符串,并作为监听器中监听的目标。
2、监听器(listener)具体根据事件发生的业务处理模块,这里可以接收处理事件中封装的对象或字符串。
3、事件发布者(publisher)事件发生的触发者。

二、ApplicationListener 接口

ApplicationListener 接口的定义如下:

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
 
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}

  它是一个泛型接口,泛型的类型必须是 ApplicationEvent 及其子类,只要实现了这个接口,那么当容器有相应的事件触发时,就能触发 onApplicationEvent 方法。ApplicationEvent 类的子类有很多,Spring 框架自带的如下几个。

使用方法很简单,就是实现一个 ApplicationListener 接口,并且将加入到容器中就行。

复制代码
@Component
public class MyApplicationListener implements ApplicationListener<ApplicationStartedEvent> {

//    @Override
//    public void onApplicationEvent(ApplicationEvent event) {
//        System.out.println("事件触发:"+event.getClass().getName());
//    }
    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        System.out.println("事件触发:"+event.getClass().getName());
    }

}
复制代码

可以看到控制台输出:这样就触发了spring默认的一些事件。

事件触发:org.springframework.boot.context.event.ApplicationStartedEvent
事件触发:org.springframework.boot.context.event.ApplicationReadyEvent

自定义事件监听

定义事件
首先,我们需要定义一个时间(MyTestEvent),需要继承Spring的ApplicationEvent

复制代码
public class MyTestEvent extends ApplicationEvent {

    private static final long serialVersionUID = 1L;

    private String msg ;

    public MyTestEvent(Object source,String msg) {
        super(source);
        this.msg = msg;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}
复制代码

定义监听器
需要定义一下监听器,自己定义的监听器需要实现ApplicationListener,同时泛型参数要加上自己要监听的事件Class名,在重写的方法onApplicationEvent中,添加自己的业务处理:

复制代码
@Component
public class MyNoAnnotationListener implements ApplicationListener<MyTestEvent> {

    @Override
    public void onApplicationEvent(MyTestEvent event) {
        System.out.println("非注解监听器:" + event.getMsg());
    }

}
复制代码

事件发布
有了事件,有了事件监听者,那么什么时候触发这个事件呢?每次想让监听器收到事件通知的时候,就可以调用一下事件发布的操作。首先在类里自动注入了ApplicationEventPublisher,这个也就是我们的ApplicationContext,它实现了这个接口。

复制代码
@RestController
@RequestMapping("testEventController")
public class MyTestEventController {

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @RequestMapping(value = "/testPublishEvent1" )
    public void testPublishEvent(){
        applicationEventPublisher.publishEvent(new MyTestEvent(this, "我来了"));
    }

}
复制代码

输出结果如下图所示:

非注解监听器:我来了

三、@EventListener 注解

从Spring 4.2以后,事件处理不用实现ApplicationListener 的 onApplicationEvent方法了,使用注解@EventListener可以自动关联相关的ApplicationListener。

复制代码
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EventListener {
    @AliasFor("classes")
    Class<?>[] value() default {};  //监听的类
 
    @AliasFor("value")
    Class<?>[] classes() default {};
 
    String condition() default "";
}
复制代码

简单使用
除了通过实现接口,还可以使用@EventListener 注解,实现对任意的方法都能监听事件。
在任意方法上标注@EventListener 注解,指定 classes,即需要处理的事件类型,一般就是 ApplicationEven 及其子类,可以设置多项。

复制代码
@Compoment
public class CustomListener {

    @EventListener(classes = {SpringApplicationEvent.class})
    public void listen(SpringApplicationEvent event) {
        System.out.println("注解事件触发:" + event.getClass().getName());
    }

}
复制代码

启动项目

可以看到控制台和之前的输出是一样的:

注解事件触发:org.springframework.boot.context.event.ApplicationStartedEvent
注解事件触发:org.springframework.boot.context.event.ApplicationReadyEvent

使用注解的好处是不用每次都去实现ApplicationListener,可以在一个class中定义多个方法,用@EventListener来做方法级别的注解。
和上面类似,事件以及事件发布不需要改变,只要这样定义监听器即可。

此时,就可以有一个发布,两个监听器监听到发布的消息了,一个是注解方式,一个是非注解方式
结果:

注解监听器----1:我来了
非注解监听器:我来了

原理

@Component
public class MyAnnotationListener {

    @EventListener
    public void listener1(MyTestEvent event) {
        System.out.println("注解监听器1:" + event.getMsg());
    }
}

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

@Component
public class MyAnnotationListener implements ApplicationListener<MyTestEvent> {
    
    @Override
    public void onApplicationEvent(MyTestEvent event) {
         System.out.println("注解监听器1:" + event.getMsg());
    }
}

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

查看SpringBoot的源码,找到下面的代码,因为我是Tomcat环境,这里创建的ApplicationContextorg.springframework.bootweb.servlet.context.AnnotationConfigServletWebServerApplicationContext

复制代码
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);
    }
复制代码

他的构造方法如下:

public AnnotationConfigServletWebServerApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

进到AnnotatedBeanDefinitionReader里面

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的后置处理器。

复制代码
public static Set<BeanDefinitionHolder> 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的监听系统里了。

复制代码
    @Override
    public void afterSingletonsInstantiated() {
        ConfigurableListableBeanFactory beanFactory = this.beanFactory;
        Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
        String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
        for (String beanName : beanNames) {
            if (!ScopedProxyUtils.isScopedTarget(beanName)) {
                Class<?> type = null;
                try {
                    type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
                }
                catch (Throwable ex) {
                    // An unresolvable bean type, probably from a lazy bean - let's ignore it.
                    if (logger.isDebugEnabled()) {
                        logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
                    }
                }
                if (type != null) {
                    if (ScopedObject.class.isAssignableFrom(type)) {
                        try {
                            Class<?> targetClass = AutoProxyUtils.determineTargetClass(
                                    beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
                            if (targetClass != null) {
                                type = targetClass;
                            }
                        }
                        catch (Throwable ex) {
                            // An invalid scoped proxy arrangement - let's ignore it.
                            if (logger.isDebugEnabled()) {
                                logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
                            }
                        }
                    }
                    try {
                        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) {
        if (!this.nonAnnotatedClasses.contains(targetType) &&
                !targetType.getName().startsWith("java") &&
                !isSpringContainerClass(targetType)) {

            Map<Method, EventListener> annotatedMethods = null;
            try {
                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);
                }
            }

            if (CollectionUtils.isEmpty(annotatedMethods)) {
                this.nonAnnotatedClasses.add(targetType);
                if (logger.isTraceEnabled()) {
                    logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
                }
            }
            else {
                // 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");
                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;
                        }
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
                            beanName + "': " + annotatedMethods);
                }
            }
        }
    }
复制代码

由方法生成Listener的逻辑由EventListenerFactory完成的,这又分为两种,一种是普通的@EventLintener 另一种是@TransactionalEventListener ,是由两个工厂处理的。


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

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

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

总结:

  1. 同样的事件能有多个监听器 -- 经过测试是可以的
  2. 事件监听操作和发布事件的操作是同步的吗? -- 是的,所以如果有事务,监听操作也在事务内。如果需要改为异步也可以手动使用多线程或者借用异步注解实现。
  3. EventListener这个注解其实可以接受参数来表示事件源的,有两个参数classes和condition,顾明思议前者是表示哪一个事件类,后者是当满足什么条件是会调用该方法,但其实都可以不用用到,直接在方法上写参数xxEvent就行

摘自:https://blog.csdn.net/m0_49558851/article/details/118903432

定义event事件模型

  首先定义一个event事件模型。ComplaintDTO为事件发布者传送给事件监听者的一些信息,入投诉的订单信息、客户信息等。可根据自身需要进行调整,调整之后需要变动相应的get/set方法和构造方法。

复制代码
import org.springframework.context.ApplicationEvent;

public class ComplaintEvent extends ApplicationEvent {

    private ComplaintDTO complaintDTO;

    public ComplaintEvent(Object source,ComplaintDTO complaintDTO) {
        super(source);
        this.complaintDTO = complaintDTO;
    }

    public ComplaintDTO getComplaintDTO() {
        return complaintDTO;
    }

    public void setComplaintDTO(ComplaintDTO complaintDTO) {
        this.complaintDTO = complaintDTO;
    }
}
复制代码

发布事件

复制代码
@Autowired
private ApplicationEventPublisher applicationEventPublisher;

@Override
public ComplaintVO createComplaint(ComplaintDTO complaintDTO) {
    //TODO 你的业务代码
    //发负一屏消息和短信
    try{
        ComplaintEvent complaintEvent = new ComplaintEvent(this,complaintDTO);
        applicationEventPublisher.publishEvent(complaintEvent);
    }catch (Exception e){
        log.info("投诉发短信或负一屏消息失败:[{}]",e.getMessage());
    }
    vo = Transferor.entity(po, ComplaintVO.class);
    return vo;
}
复制代码

事件监听者

事件的监听者实现ApplicationListener接口,重写onApplicationEvent方法实现事件处理
这里需要注意的是ApplicationEvent默认并不是异步的,如果需要异步需要我们在方法上加上@Async注解,并在启动类添加@EnableAsync开启异步

复制代码
@Log4j2
@Component
public class ComplaintEventListener implements ApplicationListener<ComplaintEvent> {
    @Async
    @Override
    public void onApplicationEvent(ComplaintEvent event) {
        log.info("订单投诉发短信与负一屏消息:[{}]", JSON.toJSONString(event));
        //发短信
        try {
            sendSmsMsg(event);
        }catch (Exception e){
            log.info("订单投诉发短信失败:[{}]",e.getMessage());
        }
        //发负一屏消息
        try {
            sendHwPubMsg(event);
        }catch (Exception e){
            log.info("订单投诉发负一屏消息失败:[{}]",e.getMessage());
        }
    }
}
复制代码

从Spring 4.2以后,事件处理不用实现ApplicationListener 的 onApplicationEvent方法了,使用注解@EventListener可以自动关联相关的ApplicationListener。
所以上面的代码其实可以改成成下面的样子

复制代码
@Log4j2
@Component
public class ComplaintEventListener{
    @Async
    @EventListener
    public void sendMsg(ComplaintEvent event) {
        log.info("订单投诉发短信与负一屏消息:[{}]", JSON.toJSONString(event));
        //发短信
        try {
            sendSmsMsg(event);
        }catch (Exception e){
            log.info("订单投诉发短信失败:[{}]",e.getMessage());
        }
        //发负一屏消息
        try {
            sendHwPubMsg(event);
        }catch (Exception e){
            log.info("订单投诉发负一屏消息失败:[{}]",e.getMessage());
        }
    }
}
复制代码

 

摘自:https://fangshixiang.blog.csdn.net/article/details/91897175

Spring事务监听机制---使用@TransactionalEventListener处理数据库事务提交成功后再执行操作

@TransactionalEventListener
  首先不得不说,从命名中就可以直接看出,它就是个EventListener
在Spring4.2+,有一种叫做@TransactionEventListener的方式,能够 控制 在事务的时候Event事件的处理方式。

  我们知道,Spring的事件监听机制(发布订阅模型)实际上并不是异步的(默认情况下),而是同步的来将代码进行解耦。而@TransactionEventListener仍是通过这种方式,只不过加入了回调的方式来解决,这样就能够在事务进行Commited,Rollback…等的时候才会去进行Event的处理,达到事务同步的目的

Demo演示

复制代码
@Slf4j
@Service
public class HelloServiceImpl implements HelloService {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Transactional
    @Override
    public Object hello(Integer id) {
        // 向数据库插入一条记录
        String sql = "insert into user (id,name,age) values (" + id + ",'fsx',21)";
        jdbcTemplate.update(sql);

        // 发布一个自定义的事件~~~
        applicationEventPublisher.publishEvent(new MyAfterTransactionEvent("我是和事务相关的事件,请事务提交后执行我~~~", id));
        return "service hello";
    }

    @Slf4j
    @Component
    private static class MyTransactionListener {
        @Autowired
        private JdbcTemplate jdbcTemplate;

        @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
        private void onHelloEvent(HelloServiceImpl.MyAfterTransactionEvent event) {
            Object source = event.getSource();
            Integer id = event.getId();

            String query = "select count(1) from user where id = " + id;
            Integer count = jdbcTemplate.queryForObject(query, Integer.class);
            
            // 可以看到 这里的count是1  它肯定是在上面事务提交之后才会执行的
            log.info(source + ":" + count.toString()); //我是和事务相关的事件,请事务提交后执行我~~~:1
        }
    }

    // 定一个事件,继承自ApplicationEvent 
    private static class MyAfterTransactionEvent extends ApplicationEvent {

        private Integer id;

        public MyAfterTransactionEvent(Object source, Integer id) {
            super(source);
            this.id = id;
        }

        public Integer getId() {
            return id;
        }
    }
}
复制代码

首先确认,通过@TransactionalEventListener注解的方式,是完全可以处理这种事务问题的。
接下来先看看这个注解本身,有哪些属性是我们可用、可控的:

复制代码
// @since 4.2  显然,注解的方式提供得还是挺晚的,而API的方式第一个版本就已经提供了
// 另外最重要的是,它头上有一个注解:`@EventListener`  so  
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@EventListener //有类似于注解继承的效果
public @interface TransactionalEventListener {
    // 这个注解取值有:BEFORE_COMMIT、AFTER_COMMIT、AFTER_ROLLBACK、AFTER_COMPLETION
    // 各个值都代表什么意思表达什么功能,非常清晰~
    // 需要注意的是:AFTER_COMMIT + AFTER_COMPLETION是可以同时生效的
    // AFTER_ROLLBACK + AFTER_COMPLETION是可以同时生效的
    TransactionPhase phase() default TransactionPhase.AFTER_COMMIT;

    // 若没有事务的时候,对应的event是否已经执行  默认值为false表示  没事务就不执行了
    boolean fallbackExecution() default false;

    // 这里巧妙的用到了@AliasFor的能力,放到了@EventListener身上
    // 注意:一般我建议都需要指定此值,否则默认可以处理所有类型的事件  范围太广了
    @AliasFor(annotation = EventListener.class, attribute = "classes")
    Class<?>[] value() default {};
    @AliasFor(annotation = EventListener.class, attribute = "classes")
    Class<?>[] classes() default {};
    
    String condition() default "";
}
复制代码

可以看到它实际上相当于在@EventListener的基础上扩展了两个属性,来对事务针对性的处理。
根据前面的Spring事件监听机制的理论知识得知:它的注册原理显然也在EventListenerMethodProcessor中,只不过它使用的是TransactionalEventListenerFactory最终来生成一个Adapter适配器:

复制代码
public class TransactionalEventListenerFactory implements EventListenerFactory, Ordered {
    private int order = 50; // 执行时机还是比较早的~~~(默认的工厂是最低优先级)
    
    // 显然这个工厂只会生成标注有此注解的handler~~~
    @Override
    public boolean supportsMethod(Method method) {
        return AnnotatedElementUtils.hasAnnotation(method, TransactionalEventListener.class);
    }

    // 这里使用的是ApplicationListenerMethodTransactionalAdapter,而非ApplicationListenerMethodAdapter
    // 虽然ApplicationListenerMethodTransactionalAdapter是它的子类
    @Override
    public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
        return new ApplicationListenerMethodTransactionalAdapter(beanName, type, method);
    }
}
复制代码

  通过这个工厂,会把每个标注有@TransactionalEventListener注解的方法最终都包装成一个ApplicationListenerMethodTransactionalAdapter,它是一个ApplicationListener,最终注册进事件发射器的容器里面。

ApplicationListenerMethodTransactionalAdapter

它是包装@TransactionalEventListener的适配器,继承自ApplicationListenerMethodAdapter~

复制代码
// @since 4.2
class ApplicationListenerMethodTransactionalAdapter extends ApplicationListenerMethodAdapter {

    private final TransactionalEventListener annotation;

    // 构造函数
    public ApplicationListenerMethodTransactionalAdapter(String beanName, Class<?> targetClass, Method method) {
        // 这一步的初始化交给父类,做了很多事情   强烈建议看看上面推荐的事件/监听的博文
        super(beanName, targetClass, method);

        // 自己个性化的:和事务相关
        TransactionalEventListener ann = AnnotatedElementUtils.findMergedAnnotation(method, TransactionalEventListener.class);
        if (ann == null) {
            throw new IllegalStateException("No TransactionalEventListener annotation found on method: " + method);
        }
        this.annotation = ann;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        // 若**存在事务**:毫无疑问 就注册一个同步器进去~~
        if (TransactionSynchronizationManager.isSynchronizationActive()) {
            TransactionSynchronization transactionSynchronization = createTransactionSynchronization(event);
            TransactionSynchronizationManager.registerSynchronization(transactionSynchronization);
        }
        // 若fallbackExecution=true,那就是表示即使没有事务  也会执行handler
        else if (this.annotation.fallbackExecution()) {
            if (this.annotation.phase() == TransactionPhase.AFTER_ROLLBACK && logger.isWarnEnabled()) {
                logger.warn("Processing " + event + " as a fallback execution on AFTER_ROLLBACK phase");
            }
            processEvent(event);
        }
        else {
            // No transactional event execution at all
            // 若没有事务,输出一个debug信息,表示这个监听器没有执行~~~~
            if (logger.isDebugEnabled()) {
                logger.debug("No transaction is active - skipping " + event);
            }
        }
    }

    // TransactionSynchronizationEventAdapter是一个内部类,它是一个TransactionSynchronization同步器
    // 此类实现也比较简单,它的order由listener.getOrder();来决定
    private TransactionSynchronization createTransactionSynchronization(ApplicationEvent event) {
        return new TransactionSynchronizationEventAdapter(this, event, this.annotation.phase());
    }


    private static class TransactionSynchronizationEventAdapter extends TransactionSynchronizationAdapter {

        private final ApplicationListenerMethodAdapter listener;
        private final ApplicationEvent event;
        private final TransactionPhase phase;

        public TransactionSynchronizationEventAdapter(ApplicationListenerMethodAdapter listener,
                ApplicationEvent event, TransactionPhase phase) {
            this.listener = listener;
            this.event = event;
            this.phase = phase;
        }

        // 它的order又监听器本身来决定  
        @Override
        public int getOrder() {
            return this.listener.getOrder();
        }

        // 最终都是委托给了listenner来真正的执行处理  来执行最终处理逻辑(也就是解析classes、condtion、执行方法体等等)
        @Override
        public void beforeCommit(boolean readOnly) {
            if (this.phase == TransactionPhase.BEFORE_COMMIT) {
                processEvent();
            }
        }

        // 此处结合status和phase   判断是否应该执行~~~~
        // 此处小技巧:我们发现TransactionPhase.AFTER_COMMIT也是放在了此处执行的,只是它结合了status进行判断而已~~~
        @Override
        public void afterCompletion(int status) {
            if (this.phase == TransactionPhase.AFTER_COMMIT && status == STATUS_COMMITTED) {
                processEvent();
            } else if (this.phase == TransactionPhase.AFTER_ROLLBACK && status == STATUS_ROLLED_BACK) {
                processEvent();
            } else if (this.phase == TransactionPhase.AFTER_COMPLETION) {
                processEvent();
            }
        }

        protected void processEvent() {
            this.listener.processEvent(this.event);
        }
    }
}
复制代码

从源码里可以看出,其实@TransactionalEventListener的底层实现原理还是事务同步器:TransactionSynchronization和TransactionSynchronizationManager。

以上,建立在小伙伴已经知晓了Spring事件/监听机制的基础上,回头看Spring事务的监听机制其实就非常非常的简单了(没有多少新东西)。

至于在平时业务编码中处理Spring的事务同步的时候选择哪种方式呢??我觉得两种方式都是ok的,看各位的喜好了(我个人偏爱注解方式,耦合度低很多并且还可以使用事件链,有时候非常好使)

需要提一句:@TransactionalEventListener@EventListener一样是存在一个加载时机问题的,若你对加载时机有严格要求和把控,建议使用API的方式而非注解方式,避免监听器未被执行而导致逻辑出错~


 摘自:https://www.jianshu.com/p/96181bba0326

spring event demo - 异步模式

加上配置,注入一个simpleApplicationEventMulticaster。将这个multicaster的taskexecutor设置为自定义的线程池。
当publish event时,当前线程会到从线程池里来取线程,进行invoke listener,以及执行subscriber逻辑。

复制代码
@Configuration
public class EventConfig {

    @Bean(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME)
    public SimpleApplicationEventMulticaster myEventMulticaster(){
        SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster();
        simpleApplicationEventMulticaster.setTaskExecutor(taskExecutor());
        return simpleApplicationEventMulticaster;
    }
    
    @Bean
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(100);
        executor.setKeepAliveSeconds(300);
        executor.setThreadNamePrefix("thread-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }
}
复制代码

或者这样传入配置的线程池

@Bean
    public SimpleApplicationEventMulticaster applicationEventMulticaster(@Qualifier("defaultThreadPoolExecutor") ThreadPoolExecutor defaultThreadPoolExecutor) {
        SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster();
        simpleApplicationEventMulticaster.setTaskExecutor(defaultThreadPoolExecutor);
        return simpleApplicationEventMulticaster;
    }

output:
从output可以看出,主线程publish event,而subscriber内容由线程池中的线程执行。

Thread main: Publish Event
thread-1: Subscribed event - test

源码解析

复制代码
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

/*setTaskExecutor

Set the TaskExecutor to execute application listeners with.
Default is a SyncTaskExecutor, executing the listeners synchronously in the calling thread.
Consider specifying an asynchronous TaskExecutor here to not block the caller until all listeners have been executed. However, note that asynchronous execution will not participate in the caller's thread context (class loader, transaction association) unless the TaskExecutor explicitly supports this.
*/
    public void setTaskExecutor(@Nullable Executor taskExecutor) {
        this.taskExecutor = taskExecutor;
    }
}
复制代码

Spring容器中的通知机制是如何实现的

初始化SimpleApplicationEventMulticaster并注入容器

Spring在初始化bean时,会进行ApplicationEventMulticaster的初始化。
会先检查是否有local的applicationEventMulticaster,如果有,那么就会创建local也就是自定义的applicationEventMulticaster,放入容器;如果没有,就会创建默认的SimpleApplicationEventMulticaster放入容器。

复制代码
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
        if (beanFactory.containsLocalBean("applicationEventMulticaster")) {
            this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        } else {
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No 'applicationEventMulticaster' bean, using [" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
            }
        }
    }

}
复制代码

注册所有的监听器

接下来,spring容器会注册所有的监听器:

复制代码
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    protected void registerListeners() {
        Iterator var1 = this.getApplicationListeners().iterator();

        while(var1.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var1.next();
            this.getApplicationEventMulticaster().addApplicationListener(listener);
        }

        String[] listenerBeanNames = this.getBeanNamesForType(ApplicationListener.class, true, false);
        String[] var7 = listenerBeanNames;
        int var3 = listenerBeanNames.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            String listenerBeanName = var7[var4];
            this.getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
            Iterator var9 = earlyEventsToProcess.iterator();

            while(var9.hasNext()) {
                ApplicationEvent earlyEvent = (ApplicationEvent)var9.next();
                this.getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }
    }

}
复制代码

 addApplicationListener会将listener和相应的事件类型记录下来:

复制代码
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {

    public void addApplicationListener(ApplicationListener<?> listener) {
        synchronized(this.defaultRetriever) {
            Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
            if (singletonTarget instanceof ApplicationListener) {
                this.defaultRetriever.applicationListeners.remove(singletonTarget);
            }

            this.defaultRetriever.applicationListeners.add(listener);
            this.retrieverCache.clear();
        }
    }

}
复制代码

事件发生时,multicast event

  • 调用multicaster的multicastEvent方法
    上面已经提到,事件发生时,会调用AbstractApplicationContext的publishEvent方法,它会调用注入到容器里的multicaster执行multicastEvent。

  • 根据事件类型,找到所有监听这类事件的listener

Iterator var5 = this.getApplicationListeners(event, type).iterator();

详细看下getApplicationListeners方法:

复制代码
    protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
        Object source = event.getSource();
        Class<?> sourceType = source != null ? source.getClass() : null;
        AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType);
        AbstractApplicationEventMulticaster.CachedListenerRetriever newRetriever = null;
        AbstractApplicationEventMulticaster.CachedListenerRetriever existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.get(cacheKey);
        if (existingRetriever == null && (this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
            newRetriever = new AbstractApplicationEventMulticaster.CachedListenerRetriever();
            existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
            if (existingRetriever != null) {
                newRetriever = null;
            }
        }

        if (existingRetriever != null) {
            Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
            if (result != null) {
                return result;
            }
        }

        return this.retrieveApplicationListeners(eventType, sourceType, newRetriever);
    }
复制代码
  •  对于每一个listener,invoke该listener
复制代码
        while(var5.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var5.next();
            if (executor != null) {
                executor.execute(() -> {
                    this.invokeListener(listener, event);
                });
            } else {
                this.invokeListener(listener, event);
            }
        }
复制代码

 



参考文章:

https://blog.csdn.net/erbao_2014/article/details/68924231

https://www.huangchaoyu.com/2020/08/08/SpringBoot-%E6%B6%88%E6%81%AF%E6%9C%BA%E5%88%B6,EventListener%E6%B3%A8%E8%A7%A3%E5%8E%9F%E7%90%86

posted @   字节悦动  阅读(2991)  评论(1编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示

目录导航