栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

发现个没见过的东西。记录一下。监听器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;

    
    public EnumUserOperate getByValue(Integer value) {
        EnumUserOperate[] values = EnumUserOperate.values();
        for (EnumUserOperate e : values) {
            if (Objects.equals(e.getValue(), value))
                return e;
        }
        return null;
    }
关键 UserActionEvent事件对象

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

@EqualsAndHashCode(callSuper = true)
public class UserActionEvent extends ApplicationEvent {

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

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

}
@EventListener()事件监听注解

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

@Service
@Slf4j
public class UserMonitor {

    
    // 异步操作。指定线程池
    @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`启用异步操作

最终执行效果

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/720933.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号