发现个没见过的东西。记录一下。监听器ApplicationEvent。顺便复习一波自定义线程池

    • 他是啥
    • 关键类
    • 示例代码
      • User对象
      • EnumUserOperate
    • `关键`
      • UserActionEvent事件对象
      • @EventListener()事件监听注解
      • ApplicationEventPublisher事件发布器
      • AsyncConfigurer自定义线程池

处于好奇我就百度了一下,琢磨了一下,参考了一个戏精博主的文章,写了个demo,这里记录一下

他是啥

首先这玩意呢,就是一个监听器,他可以监听指定类型的事件
事件类继承ApplicationEvent,在里面自定义荷载,由事件发布器ApplicationEventPublisher 调用方法.publishEvent(userActionEvent);发布,一但发布马上就会被@EventListener()定义好的监听器监听到,从而执行方法内的内容

关键类

ApplicationEvent,基础事件抽象类,继承这个类以后,类就成为了可发布事件,可以使用发布器对事件进行发布
ApplicationEventPublisher,事件发布器,可以调用publishEvent发布我们定义好的事件
@EventListener ,监听器配置注解,配置监听器参数,value=监听的具体事件,condition表达式监听的匹配规则,#参数…event的operate的name==“ADD“
AsyncConfigurer,自定义线程池,事件监听有的业务需要避免阻塞线程,所以我们定义一个线程池。避免异步调用的时候频繁销毁创建线程

示例代码

User对象

任意一个POJO提供测试即可

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private Long id;
    private String name;
    private String gender;
    private Integer age;

    public User(Long id, String name) {
        this.id = id;
        this.name = name;
    }
}

EnumUserOperate

状态枚举,便于状态的维护

public enum EnumUserOperate {
    ADD("add", 0, "新增"),
    UPDATE("update", 1, "修改"),
    DELETE("delete", 2, "删除");

    private String name;
    private Integer value;
    private String desc;

    /**
     * 根据value获取枚举实例
     * @param value
     * @return
     */
    public EnumUserOperate getByValue(Integer value) {
        EnumUserOperate[] values = EnumUserOperate.values();
        for (EnumUserOperate e : values) {
            if (Objects.equals(e.getValue(), value))
                return e;
        }
        return null;
    }

关键

UserActionEvent事件对象

这个就是用来被监听的对象了,当事件发布器发布这个事件的时候,监听这个事件的监听器将被触发

/**
 * 事件详情辅助对象,用以辅助事件的发布,发布的时候就发布这货,至于里面有什么,自己根据情况而定
 * 届时那货也接Object,但是没意义,最好用这个定义好的,然后利用多态转型,以辅助事件的进行
 */
@EqualsAndHashCode(callSuper = true)
public class UserActionEvent extends ApplicationEvent {

    // 操作是否成功
    private Boolean success;
    // 操作类型
    private EnumUserOperate operate;
    // 数据对象
    private User user;

    /**
     * Create a new {@code ApplicationEvent}.
     *
     * @param source the object on which the event initially occurred or with
     *               which the event is associated (never {@code null})
     */
    public UserActionEvent(Object source) {
        super(source);
    }

}

@EventListener()事件监听注解

用以配置监听器,触发的时候将会执行监听器注解的那个方法

@Service
@Slf4j
public class UserMonitor {

    /**
     * 监听新增用户事件
     * 异步操作使用自定义线程池
     * EventListener注解中细化监听具体某种事件
     * @param event 监听事件
     * @return
     */
    // 异步操作。指定线程池
    @Async("lazyTraceExecutor")
    // 配置监听器,value=监听的具体事件,condition监听的匹配规则,#参数....event的operate的name==“ADD“
    @EventListener(value = UserActionEvent.class,condition = "#event.operate.name()=='ADD'")
    public void addUserApplicationEvent(UserActionEvent event){
        try {
            User user = event.getUser();
            log.info("监听到新增用户,:{}",user);
            log.info("具体的操作,可以是新增以后的很多事情");
        } catch (Exception e) {
            log.error("事件:{},执行异常:{}",event,e.getMessage());
        }
    }
}

ApplicationEventPublisher事件发布器

在任意一个地方注入这个bean就可以调用方事件的发布

@Service
public class UserServiceImpl implements UserService {

    // 注入事件发布器
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Override
    public User addUser(User user) {
        // 这里本该进行dao层操作,由于只是演示。直接使用入参对象返回。表示保存成功了
        // 添加用户操作,发布通知:新增了user
        User saveResult = saveUser(user);
        UserActionEvent userActionEvent = new UserActionEvent(this);
        userActionEvent.setOperate(EnumUserOperate.ADD);
        userActionEvent.setSuccess(true);
        userActionEvent.setUser(saveResult);
        // 调用事件发布器,发布事件
        applicationEventPublisher.publishEvent(userActionEvent);
        log.info("发布了add事件:{}",userActionEvent);
        return saveResult;
    }
    // 模拟一波DB操作
    public User saveUser(User user){
        return user;
    }
}

AsyncConfigurer自定义线程池

配置一波自定义线程池

@Configuration
public class MyAsynConfigurer implements AsyncConfigurer {

    /**
     * 自定义线程池
     */
    @Bean("lazyTraceExecutor")
    public Executor getAsynExecutor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 获取虚拟机可用的处理器最大数量
        int core = Runtime.getRuntime().availableProcessors();

        executor.setCorePoolSize(core); // 设置核心线程数
        executor.setMaxPoolSize(core*2+1); // 设置最大线程数量
        executor.setKeepAliveSeconds(3); // 除核心线程外,其他线程的最大存活时间
        executor.setQueueCapacity(40); // 设置队列容量,如果传入值大于0,底层队列使用的是LinkedBlockingQueue,否则默认使用SynchronousQueue
        executor.setThreadNamePrefix("jvm-executor-"); // 设置线程名称前缀
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 设置线程的拒绝策略
        executor.initialize(); // 执行初始化
        return executor;
    }
}
在使用@Async("lazyTraceExecutor")进行异步操作的时候就可以通过指定这个异步方案bean的id名进行线程池的选用
注意需要在启动类上添加注解`@EnableAsync`启用异步操作

最终执行效果
发现个没见过的东西。记录一下。监听器ApplicationEvent。顺便复习一波自定义线程池_第1张图片

你可能感兴趣的:(java,springboot,java,开发语言,后端)