springBoot的event事件发布/监听

110 篇文章 2 订阅
34 篇文章 0 订阅

先定义一个Event父类

package com.felix.event;

import org.springframework.context.ApplicationEvent;

public class BaseEvent extends ApplicationEvent {

    public BaseEvent(Object source) {
        super(source);
    }

}

自定义的Event类继承BaseEvent父类

package com.felix.event;

/**
 * 自定义的Event
 */
public class SelfEvent extends BaseEvent{

    public SelfEvent(Object source) {
        //可以做点事情
        super(source);
        //可以做点事情
    }

}

发布消息

package com.felix.event.publish;

import com.felix.event.SelfEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

@Service
public class SelfHandler {

    @Autowired
    private ApplicationContext applicationContext;


    public void handler(){
        for(int i = 0;i < 1000; i ++){

            Map test = new HashMap();
            test.put("index",i);
            test.put("name","袁成舟");
            test.put("sex","male");
            test.put("age","26");

            /**
             * 这边使用多线程发布的时候
             * 消费者那边实现 ApplicationListener<SelfEvent> 这个接口的消费者消费的时候不是有序消费的
             */
            CompletableFuture.runAsync(() -> {
                applicationContext.publishEvent(new SelfEvent(test));
            });

        }

    }

}

监听事件

这里要注意实现ApplicationListener接口的监听者监听的时候不是有序的,上面我采用多线程实验了一波实锤了。

注意
如果发布和监听都没有采用异步,即发布处是一个for循环,监听者没有开启异步,那么两者就是同步的。发布者发完一个要等监听者处理完之后才能发布第二个事件,发布者在监听者没有返回ack的时候是阻塞的。
举个栗子:
发布者发布了100个事件,在发布这100个事件发布过程中,会等上一个事件处理完成之后再发布下一个事件,等同于整个是个同步的过程。
如果就是要监听者异步去监听处理,可以在监听者类上加上@EnableAsync,在onApplicationEvent方法上加上@Async异步注解

package com.felix.event.consumer;

import com.felix.event.SelfEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class SelfEventListener implements ApplicationListener<SelfEvent> {

    @Override
    public void onApplicationEvent(SelfEvent selfEvent) {
        System.out.println("收到自定义的SelfEvent事件了-------" + selfEvent.getSource());
    }
}

在这里插入图片描述

上面这样写虽然已经很简单了,但是在springboot下,还是可以使用注解进行进一步的简化

发布者

发布者这里新建了一个工具类,实现了ApplicationEventPublisherAware接口,可以注入ApplicationEventPublisher,注入原理类似BeanNameAware接口.

package com.felix.event.tool;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;

@Component
public class SpringApplicationEventPublishUtil implements ApplicationEventPublisherAware {


    private ApplicationEventPublisher publisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }

    public void publishEvent(ApplicationEvent event){
        publisher.publishEvent(event);
    }

}

注解形式的监听者方法

监听的方法一次可以监听多个事件
而且当多个方法监听一个事件的时候,可以按照自定义的顺序去执行这些个方法,即这些监听同一个事件的方法都会执行的,只是执行的时候有序了而已

@Order(1)注解就是定义顺序的,数字越小,执行顺序越靠前

package com.felix.event.consumer;

import com.felix.event.tool.FaceEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class AnnotationConsumer {


    /**
     *  如果要监听多个事件类型的发布,可以在@EventListener(classes = {FaceEvent.class,ArmEvent.class})指定,
     *  spring会多次调用此方法来处理多个事件。但是注意此时,方法参数不能有多个,否则会发生转换异常,
     *  可以将使用多个事件的父类作为唯一的方法参数来接收处理事件,但除非必要否则并不推荐监听多个事件的发布。
     *  可以2个方法同时监听同一个事件,并且优先级按照数字值小的先监听.
     *  不过发布者发布了一个事件,但是在有2个方法同时监听的时候这两个方法都会执行,只是执行顺序按照@Order中的值来决定
     * @param event
     */
    @EventListener(classes = {FaceEvent.class})
    @Order(1)
    public void onAnnotationEvent_1(ApplicationEvent event){
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("收到自定义的 FaceEvent 事件了,优先级=1-------{}",event.getSource());
    }

    @EventListener(classes = {FaceEvent.class})
    @Order(2)
    public void onAnnotationEvent_2(ApplicationEvent event){
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("收到自定义的 FaceEvent 事件了,优先级=2-------{}",event.getSource());
    }

}

@TransactionalEventListener和@EventListener监听事件的区别

@TransactionalEventListener@EventListener都可以监听事件,但前者可以对发布事件和监听事件进行一些事务上的隔离。@TransactionalEventListenerr指不和发布事件的方法在同一个事务内,发布事件的方法事务结束后才会执行本监听方法,监听逻辑内发生异常不会回滚发布事件方法的事务。

@TransactionalEventListener有一个属性为fallbackExecution默认为false,指发布事件的方法没有事务控制时,监听器不进行监听事件,此为默认情况! fallbackExecution=true,则指发布事件的方法没有事务控制时,监听方法仍可以监听事件进行处理。

刚才我们说到使用@TransactionalEventListener会在发布事件的方法事务结束后执行监听方法,但其实我们还可以进行细化的控制。它有一个属性为TransactionPhase,默认为TransactionPhase.AFTER_COMMIT,即事务提交后。还可以根据需要选择AFTER_COMPLETION、BEFORE_COMMIT、AFTER_ROLLBACK
但仍需注意,如果fallbackExecution=false,且发布事件的方法没有事务控制时,监听器根本不会监听到事件,此处的TransactionPhase也就没有意义了。

TransactionalEventListener坑点

如果遇到这样的业务,操作B需要在操作A事务提交后去执行,那么TransactionalEventListener是一个很好地选择。这里需要特别注意的一个点就是:当B操作有数据改动并持久化时,并希望在A操作的AFTER_COMMIT阶段执行,那么你需要将B事务声明为PROPAGATION_REQUIRES_NEW。这是因为A操作的事务提交后,事务资源可能仍然处于激活状态,如果B操作使用默认的PROPAGATION_REQUIRED的话,会直接加入到操作A的事务中,但是这时候事务A是不会再提交,结果就是程序写了修改和保存逻辑,但是数据库数据却没有发生变化,解决方案就是要明确的将操作B的事务设为PROPAGATION_REQUIRES_NEW。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Boot中的事件监听器可以通过实现ApplicationListener接口来监听特定的事件。当事件被触发时,会调用对应监听器中的方法来处理事件。 在监听事件时,可以通过event对象来获取事件的详细信息。event对象是特定事件类的实例,它包含了事件相关的数据和方法。 为了监听事件并获取event对象,首先需要创建一个监听器类,并实现ApplicationListener接口。监听器类需要指定要监听事件类型,比如: ``` public class MyEventListener implements ApplicationListener<MyEvent> { @Override public void onApplicationEvent(MyEvent event) { // 在这里处理事件 // 可以通过event对象获取事件的详细信息进行处理 } } ``` 在上述代码中,MyEvent是自定义的事件类,MyEventListener是监听事件监听器。 接下来,需要将监听器注册到Spring Boot应用中。可以通过@Component注解将监听器类标记为Spring组件,并由Spring自动扫描和注册监听器,或者通过@Configuration注解的配置类中手动注册监听器。 当事件被触发时,监听器中的onApplicationEvent方法将被调用,并传入对应的event对象。可以通过event对象来获取事件的详细信息,如: ``` public class MyEventListener implements ApplicationListener<MyEvent> { @Override public void onApplicationEvent(MyEvent event) { // 获取事件的信息 String message = event.getMessage(); Date timestamp = event.getTimestamp(); // 进行处理 } } ``` 通过以上步骤,就可以在Spring Boot应用中监听事件并获取event对象,进而处理事件

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值