ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-01-29 19:01:57  阅读:194  来源: 互联网

标签:自定义 ApplicationEvent 监听 private 线程 事件 监听器 public User



处于好奇我就百度了一下,琢磨了一下,参考了一个戏精博主的文章,写了个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,监听,private,线程,事件,监听器,public,User
来源: https://blog.csdn.net/m0_49194578/article/details/122746185

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有