天天看点

如何使用SmartApplicationListener有顺序的监听同一个事件Event

SpringBoot 有序事件监听器

如何使用SmartApplicationListener有顺序的监听同一个事件Event
实现

SmartApplicationListener

重写supportsEventType、supportsSourceType来区分是否是我们监听的事件,只有两个方法同时返回true时才会执行,getOrder这个方法可以解决执行监听的顺序问题,return的数值越小证明优先级越高,执行顺序越靠前。

用户注册发送邮件

首先创建一个事件,监听都是围绕着事件

import com.base.client.model.vo.UserVO;
import lombok.Getter;
import org.springframework.context.ApplicationEvent;

/**
 * 用户创建事件
 *
 * @author arjun
 * @date 2020/12/09
 */
@Getter
public class UserRegisterEvent extends ApplicationEvent {
    /**
     * 发送的内容
     */
    private UserVO content;

    /**
     * 重写构造器
     *
     * @param source  发送事件的对象
     * @param content 发送的内容
     */
    public UserRegisterEvent(Object source, UserVO content) {
        super(source);
        this.content = content;
    }
}
           

创建

UserService

只用于实现注册事件发布功能(当然业务逻辑也是可以写,这里只为测试)

这里注入

ApplicationEventPublisher

接口

import com.base.client.model.vo.UserVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

/**
 * @author arjun
 * @date 2020/12/09
 */
@Service
public class UserService {

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    public void register(UserVO vo) {
        System.out.println("----------------发布注册事件----------------------");
        // 发布 UserRegisterEvent 事件
        eventPublisher.publishEvent(new UserRegisterEvent(this, vo));
    }
}
           

ApplicationEvent

监听所有事件发布,

SmartApplicationListener

接口添加了两个方法

supportsEventType

supportsSourceType

来区分是否是我们监听的事件,只有两个方法同时返回true时才会执行

onApplicationEvent

getOrder

这个方法可以解决执行监听的顺序问题,return的数值越小证明优先级越高,执行顺序越靠前。

import com.base.client.model.vo.UserVO;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component;

/**
 * @author arjun
 * @date 2020/12/09
 */
@Component
public class UserRegisterListener implements SmartApplicationListener {
    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
        return aClass == UserRegisterEvent.class;
    }

    @Override
    public boolean supportsSourceType(Class<?> sourceType) {
        return sourceType == UserService.class;
    }

    @Override
    public int getOrder() {
        return 2;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        System.out.println("----------------监听用户注册----------------------");
        UserRegisterEvent registerEvent = (UserRegisterEvent) applicationEvent;
        UserVO vo = registerEvent.getContent();
        System.out.println("----------------用户正在注册----------------------");
        vo.setEmail("[email protected]");
        vo.setUserName("name");
        vo.setPassword("666");
        System.out.println("用户注册:邮箱:" + vo.getEmail() + ", 用户名:" + vo.getUserName() + ", 密码:" + vo.getPassword());
        System.out.println("----------------用户注册完成----------------------");
    }
}
           

这里return为“2”,优先级将靠后

import com.base.client.model.vo.UserVO;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component;

/**
 * 监听系统用户创建并发送邮件通知  有序监听
 *
 * @author arjun
 * @date 2020/12/09
 */
@Component
public class UserRegisterSentMailListener implements SmartApplicationListener {

    /**
     * 接收到的监听事件类型
     */
    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
        return aClass == UserRegisterEvent.class;
    }

    /**
     * 发布该事件的Source类型
     */
    @Override
    public boolean supportsSourceType(Class<?> sourceType) {
        return sourceType == UserService.class;
    }

    /**
     * 同步下监听执行顺序 -- 数值越低优先级越高
     */
    @Override
    public int getOrder() {
        return 1;
    }

    /**
     * supportsEventType & supportsSourceType 两个方法返回true 时调用该方法执行业务逻辑
     *
     * @param applicationEvent 具体的监听事件
     */
    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        System.out.println("----------------监听发送邮件----------------");
        // 转换事件类型
        UserRegisterEvent registerEvent = (UserRegisterEvent) applicationEvent;
        UserVO vo = registerEvent.getContent();
        System.out.println("----------------发送邮件----------------");
        System.out.println("发送给:" + vo.getEmail() + ", 用户名:" + vo.getUserName() + ", 密码:" + vo.getPassword());
    }
}
           

这里return为“1”,优先级将靠前

运行结果如下

----------------发布注册事件----------------------
----------------监听发送邮件----------------
----------------发送邮件----------------
发送给:null, 用户名:null, 密码:null
----------------监听用户注册----------------------
----------------用户正在注册----------------------
用户注册:邮箱:[email protected], 用户名:name, 密码:666
----------------用户注册完成----------------------
           

更改

UserRegisterListener

return为“0”,优先级提高

再次运行结果如下:

----------------发布注册事件----------------------
----------------监听用户注册----------------------
----------------用户正在注册----------------------
用户注册:邮箱:[email protected], 用户名:name, 密码:666
----------------用户注册完成----------------------
----------------监听发送邮件----------------
----------------发送邮件----------------
发送给:[email protected], 用户名:name, 密码:666
           

这次看到的输出结果的顺序就正确了,先保存信息然后再发送邮件通知。

使用@Async异步监听

在Spring中,基于

@Async

标注的方法,称之为异步方法,内部实现机制是线程池任务

ThreadPoolTaskExecutor

,通过线程池来对配置

@Async

的方法或者类做出执行动作。

任务线程池配置

创建一个

SpringAsyncConfig

,并且使用

@EnableAsync

注解开启异步处理:

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

/**
 * @author arjun
 * @date 2020/12/09
 */
@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {
    /**
     * 获取异步线程池执行对象
     */
    @Override
    public Executor getAsyncExecutor() {
        // 使用Spring内置线程池任务对象
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置线程池参数
        executor.initialize();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return null;
    }
}
           

onApplicationEvent

方法上加上

@Async

实现方法异步调用,方法里添加线程阻塞3秒

@Override
    @Async
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        System.out.println("----------------监听发送邮件----------------");
        try {
            Thread.sleep(3000);
            System.out.println("睡上3秒");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 转换事件类型
        UserRegisterEvent registerEvent = (UserRegisterEvent) applicationEvent;
        UserVO vo = registerEvent.getContent();
        System.out.println("----------------发送邮件----------------");
        System.out.println("发送给:" + vo.getEmail() + ", 用户名:" + vo.getUserName() + ", 密码:" + vo.getPassword());
    }
}
           
如果存在多个监听同一个事件,并且同时存在

同步

异步

两种执行方式,则不存在执行顺序
----------------发布注册事件----------------------
----------------监听用户注册----------------------
----------------用户正在注册----------------------
用户注册:邮箱:[email protected], 用户名:name, 密码:666
----------------用户注册完成----------------------
----------------监听发送邮件----------------
睡上3秒
----------------发送邮件----------------
发送给:[email protected], 用户名:name, 密码:666
           

同步与异步分别存在,优先级失效

继续阅读