ApplicationEvent 事件泛型封装记录

news/2024/9/20 23:18:56 标签: java

一、一个事件的封装、发布以及监听

事件类封装

把需要的信息封装到一个事件类中

@Data
public class Person {
    private String name;
}

@Data
public class PersonEvent {

    private Person person;

    private String addOrUpdate;

    public PersonEvent(Person person, String addOrUpdate) {
        this.person = person;
        this.addOrUpdate = addOrUpdate;
    }
}

事件监听处理


@Component
public class EventListenerService {

    @EventListener
    public void handlePersonEvent(PersonEvent personEvent) {
        System.out.println("handlePersonEvent 监听到 PersonEvent");
        //处理逻辑
    }

}

发布事件

@RestController
public class TestController {

    @Resource
    private ApplicationEventPublisher applicationEventPublisher;

    @GetMapping("/publishEvent")
    public void publishEvent() {
        applicationEventPublisher.publishEvent(new PersonEvent(new Person(), "add"));
    }
}

以上就是一个事件的封装、监听以及发布的过程,但我们需要的事件多了以后,每一个对象都需要一个对应的 xxxxEvent 封装对象。这样的代码过于冗余。

二、使用泛型封装

事件对象

@Data
public class MyBaseEvent<T> {
    private T data;
    private String addOrUpdate;

    public MyBaseEvent(T data, String addOrUpdate) {
        this.data = data;
        this.addOrUpdate = addOrUpdate;
    }

   
}

事件监听

@Component
public class MyBaseEventListenerService {

    
    @EventListener
    public void handleMyEvent(MyBaseEvent<?> myBaseEvent){
        Object data = myBaseEvent.getData();
        if(data instanceof Person){
            System.out.println("handleMyEvent 监听到 person");
        }else if (data instanceof Order){
            System.out.println("handleMyEvent 监听到 order");
        }
    }


}

事件发布

@Controller
@RequestMapping("/eventTest")
public class EventTestController {

    @Resource
    private ApplicationEventPublisher applicationEventPublisher;

    @GetMapping("/publishEvent")
    @ResponseBody
    public void publishEvent() {
        applicationEventPublisher.publishEvent(new MyBaseEvent(new Person(),"add"));
        applicationEventPublisher.publishEvent(new MyBaseEvent(new Order(),"add"));
    }
}

运行结果

在这里插入图片描述
结果是正常执行了,但是不同的类型监听的逻辑都在一个方法中了,如果事件的类型很多个的时候,这个监听的方法就会变的很繁琐,需要用非常多的 if 分支去做判断。

如果我们把监听拆开:

@Component
public class MyBaseEventListenerService {

    
    @EventListener
    public void handleMyEvent(MyBaseEvent<?> myBaseEvent){
        Object data = myBaseEvent.getData();
        if(data instanceof Person){
            System.out.println("handleMyEvent 监听到 person");
        }else if (data instanceof Order){
            System.out.println("handleMyEvent 监听到 order");
        }
    }


    
    @EventListener
    public void handlePersonEvent(MyBaseEvent<Person> personEvent){
        Object data = personEvent.getData();
        System.out.println("handlePersonEvent 监听到 person");
    }

    @EventListener
    public void handleOrderEvent(MyBaseEvent<Order> orderEvent){
        Object data = orderEvent.getData();
        System.out.println("handleOrderEvent 监听到 order");
    }
}

但是再次重启服务,发起调用会发现控制台没有输出了,只执行了handleMyEvent这个监听器里的:
在这里插入图片描述
对于这种情况官方的说明是由于泛型擦除的原因,在运行时,Java 的泛型会被擦除,导致事件监听器无法正确地识别事件的泛型类型。例如 handlePersonEvent(MyBaseEvent<Person> personEvent) 中的 MyBaseEvent<Person> 会被擦除成为 MyBaseEvent,因此,当你定义一个事件监听器方法时,参数类型为 MyBaseEvent<Person>,在运行时会丢失泛型信息,参数类型会变成 MyBaseEvent,而无法保留具体的泛型信息。这就会导致在事件发布时,虽然发布的是 MyBaseEvent<Person> 类型的事件,但在监听器方法中,参数类型已经丢失了泛型信息,从而导致了类型匹配问题,监听器无法正确地匹配到事件的具体类型,进而导致监听器未执行的情况发生。

官方提供了另一种实现方式:事件类实现 ResolvableTypeProvider ,重写 getResolvableType 方法,在运行期动态的获取泛型对应的真正的对象类型,从而解决了编译阶段泛型擦除的问题。

@Data
public class MyBaseEvent<T> implements ResolvableTypeProvider {
    private T data;
    private String addOrUpdate;

    public MyBaseEvent(T data, String addOrUpdate) {
        this.data = data;
        this.addOrUpdate = addOrUpdate;
    }

    
    @Override
    public ResolvableType getResolvableType() {
        return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(getData()));
    }

}

再次运行后:
在这里插入图片描述
可以看到拆开的监听器也正常执行了

原文: https://juejin.cn/post/7323793129710551080?utm_source=gold_browser_extension


http://www.niftyadmin.cn/n/5667845.html

相关文章

Linux——应用层自定义协议与序列化

目录 一应用层 1再谈 "协议" 2序列化与反序列化 3理解read,write,recv,send 4Udp vs Tcp 二网络版本计算器 三手写序列和反序列化 四进程间关系与守护进程 1进程组 1.1什么是进程组 1.2组长进程 2会话 2.1什么是会话 2.2会话下的前后台进程 3作业控…

jeecg 在用户页面展示当前账号的角色

SysUser 增加角色字段 TableField(exist false)private String roleText;/sys/user/listAll 接口增加返回值 //查询角色List<String> roleCodeByUserId sysUserRoleMapper.getRoleNameByUserId(item.getId());if (oConvertUtils.isNotEmpty(roleCodeByUserId)) {item.s…

HarmonyOS开发实战(5.0)实现二楼上划进入首页效果详解

鸿蒙HarmonyOS开发实战往期必看文章&#xff1a; HarmonyOS NEXT应用开发性能实践总结 一分钟了解”纯血版&#xff01;鸿蒙HarmonyOS Next应用开发&#xff01; 最新版&#xff01;“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线&#xff01;&#xff08;从零基础入门…

飞驰云联FTP替代方案:安全高效文件传输的新选择

FTP协议广泛应用各行业的文件传输场景中&#xff0c;由于FTP应用获取门槛低、使用普遍&#xff0c;因此大部分企业都习惯使用FTP进行文件传输。然而面临激增的数据量和网络安全威胁的不断演变&#xff0c;FTP在传输安全性与传输性能上有所欠缺&#xff0c;无法满足企业现在的高…

线性系统分析

一、定义 (1)叠加性 若 且 则称该系统具有叠加性。 叠加性:系统的一个输入不影响系统对其他输入的响应。 (2)均匀性 若 对任意常数a下式都成立 则称该系统具有均匀性。 均匀性:系统能够保持对输入信号的缩放因子不变。 (3)线性系统 若一个系统同时具有叠加性和…

如何创建模板提示prompt

定义模型 from langchain_ollama import ChatOllamallm ChatOllama(base_url"http://ip:11434",model"qwen2",temperature0,tool_choice"auto" )什么是提示模板&#xff1f; 它的目的是根据不同的输入动态生成特定格式的文本&#xff0c;以便…

深入探索:深度优先遍历与广度优先遍历的奥秘与应用

在算法和数据结构的广阔领域中&#xff0c;图的遍历是一个核心且基础的概念&#xff0c;它支撑着众多高级算法和应用的实现。深度优先遍历&#xff08;DFS&#xff09;和广度优先遍历&#xff08;BFS&#xff09;作为图的两种基本遍历方式&#xff0c;不仅具有深刻的理论意义&a…

码头童话,“丈量”行业数智化转型

作者 | 曾响铃 文 | 响铃说 一箱车厘子从地球正对的另一边远渡重洋来到中国&#xff0c;而一旦到达&#xff0c;5个小时内它就能变成北京、天津、河北、河南等区域老百姓果盘里的美味。 这一幕&#xff0c;来自央视联合华为制作发布的《新智中国说-谈智一会间》第一期“码头…