springBoot的event事件发布/监听

先定义一个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也就没有意义了。

猜你喜欢

转载自blog.csdn.net/weixin_43944305/article/details/111645778