砍材农夫砍材农夫
  • 微信记账小程序
  • java
  • redis
  • mysql
  • 场景类
  • 框架类
  • vuepress搭建
  • hexo搭建
  • 云图
  • llm wiki

    • 基于karpathy
    • gradle
  • 常用工具

    • git
    • gradle
    • Zadig
    • it-tools
    • 开源推荐
    • curl
  • 大前端

    • 环境配置
    • 微信生态
    • 正则
    • 全栈技能
  • java圈

    • java基础
    • jdk体系
    • jvm
    • spring框架
    • 分库分表
    • zookeeper
  • python技能

    • python编程
    • python数据
  • 算法

    • 算法
  • 网关

    • spring_cloud_gateway
    • openresty
  • 高可用

    • 秒杀
    • 分布式
    • 缓存一致
  • MQ

    • MQ
    • rabbitMQ
    • rocketMQ
    • kafka
  • 其它

    • 设计模式
    • 领域驱动(ddd)
  • 关系型数据库

    • mysql5.0
    • mysql8.0
  • 非关系型数据库

    • redis
    • mongoDB
  • 分布式/其他

    • ShardingSphere
    • 区块链
  • 向量数据库

    • M3E
    • OPEN AI
  • Jmeter
  • fiddler
  • wireshark
  • AI入门
  • AI大模型
  • AI插件
  • AI集成框架
  • 相关算法
  • AI训练师
  • 量化交易
  • AIoT
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 相关运营
  • devops
  • 元宇宙
  • 区块链
  • 物联网
  • webrtc
  • web3.0
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 中考
  • 投资
  • 保险
  • 思
  • 微信记账小程序
  • java
  • redis
  • mysql
  • 场景类
  • 框架类
  • vuepress搭建
  • hexo搭建
  • 云图
  • llm wiki

    • 基于karpathy
    • gradle
  • 常用工具

    • git
    • gradle
    • Zadig
    • it-tools
    • 开源推荐
    • curl
  • 大前端

    • 环境配置
    • 微信生态
    • 正则
    • 全栈技能
  • java圈

    • java基础
    • jdk体系
    • jvm
    • spring框架
    • 分库分表
    • zookeeper
  • python技能

    • python编程
    • python数据
  • 算法

    • 算法
  • 网关

    • spring_cloud_gateway
    • openresty
  • 高可用

    • 秒杀
    • 分布式
    • 缓存一致
  • MQ

    • MQ
    • rabbitMQ
    • rocketMQ
    • kafka
  • 其它

    • 设计模式
    • 领域驱动(ddd)
  • 关系型数据库

    • mysql5.0
    • mysql8.0
  • 非关系型数据库

    • redis
    • mongoDB
  • 分布式/其他

    • ShardingSphere
    • 区块链
  • 向量数据库

    • M3E
    • OPEN AI
  • Jmeter
  • fiddler
  • wireshark
  • AI入门
  • AI大模型
  • AI插件
  • AI集成框架
  • 相关算法
  • AI训练师
  • 量化交易
  • AIoT
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 相关运营
  • devops
  • 元宇宙
  • 区块链
  • 物联网
  • webrtc
  • web3.0
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 中考
  • 投资
  • 保险
  • 思
  • spring_boot

    • SpEL(表达式)

      • 概念
      • 常用命令
      • nginx安装和部署
  • spring_cloud

    • 入门

      • SpEL(表达式)

        • 概念
        • 常用命令
        • nginx安装和部署
  • spring_core

    • SpEL(表达式)

      • 概念
      • 常用命令
      • nginx安装和部署
    • spring event

      • spring event入门
      • spring event高性能
      • spring event顺序和条件
      • spring event泛化
  • spring_tools

    • 入门

      • SpEL(表达式)

        • 概念
        • 常用命令
        • nginx安装和部署
  • spring|spring event|Spring内置事件驱动编程模型|类型泛化
    • 优雅处理同类业务
    • 源码
    • 定义事件类型
    • 完整的演示案例
      • 定义事件
      • 定义不同业务类
      • 监听配置解析
      • 发布事件
      • 验证
      • 验证结果

spring|spring event|Spring内置事件驱动编程模型|类型泛化

优雅处理同类业务

需要为同一类业务(如所有“创建”操作)定义监听器,但又希望根据不同实体类型做区分处理时,泛型事件是很好的解决方案

源码

https://gitee.com/jysemel-spring/spring-boot/tree/master/action/action-event-generic

定义事件类型

package com.jysemel.spring.boot.study.event;


import lombok.Getter;
import lombok.Setter;

// 定义一个泛型事件
@Getter
@Setter
public class EntityCreatedEvent<T> {

    private T entity;
}

完整的演示案例

定义事件

  • ResolvableTypeProvider

Java的泛型在编译后,其类型参数会被擦除,导致运行时无法获取

package com.jysemel.spring.boot.study.event;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.core.ResolvableType;
import org.springframework.core.ResolvableTypeProvider;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class GenericEvent<T> implements ResolvableTypeProvider {

    private T data;
    private String operation;

    @Override
    public ResolvableType getResolvableType() {
        if (this.data != null) {
            return ResolvableType.forClassWithGenerics(
                    getClass(),
                    ResolvableType.forInstance(this.data)
            );
        }
        return ResolvableType.forClass(getClass());
    }
}

定义不同业务类

package com.jysemel.spring.boot.study.event;


import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@AllArgsConstructor
public class Order {

    private String orderId;
    private Double amount;

}
package com.jysemel.spring.boot.study.event;


import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@AllArgsConstructor
public class Person {
    private String name;
    private Integer age;
}

监听配置解析

package com.jysemel.spring.boot.study.listener;


import com.jysemel.spring.boot.study.event.GenericEvent;
import com.jysemel.spring.boot.study.event.Order;
import com.jysemel.spring.boot.study.event.Person;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class GenericEventListener {

    @PostConstruct
    public void init() {
        System.out.println("✅✅✅ GenericEventListener 已被 Spring 加载!");
    }
    /**
     * 监听 Person 类型的泛型事件
     * Spring 会根据泛型参数自动路由
     */
    @Async
    @EventListener
    public void handlePersonEvent(GenericEvent<Person> event) {
        Person person = event.getData();
        log.info("【Person监听器】操作: {}, 数据: name={}, age={}", event.getOperation(), person.getName(), person.getAge());
    }

    /**
     * 监听 Order 类型的泛型事件
     */
    @Async
    @EventListener
    public void handleOrderEvent(GenericEvent<Order> event) {
        Order order = event.getData();
        log.info("【Order监听器】操作: {}, 数据: orderId={}, amount={}", event.getOperation(), order.getOrderId(), order.getAmount());
    }

    /**
     * 监听所有类型的泛型事件(兜底)
     * 注意:SpEL 表达式可以精确控制
     */
    @Async
    @EventListener(condition = "#event.operation == 'DELETE'")
    public void handleAllDeleteEvent(GenericEvent<?> event) {
        log.info("【通用删除监听器】操作: DELETE, 数据: {}", event.getData());
    }

    @EventListener
    @Async
    public void handleRawEvent(GenericEvent event) {
        System.out.println("🔥🔥🔥【兜底原始类型】成功捕获事件,数据为: " + event.getData());
    }
}

发布事件

package com.jysemel.spring.boot.study.service;


import com.jysemel.spring.boot.study.event.GenericEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

@Component
public class EventPublisher {

    @Autowired
    private  ApplicationEventPublisher publisher;

    /**
     * 发布泛型事件
     * @param data      业务数据(任意类型)
     * @param operation 操作类型
     * @param <T>       数据类型
     */
    public <T> void publish(T data, String operation) {
        GenericEvent<T> event = new GenericEvent<>(data, operation);
        publisher.publishEvent(event);
        System.out.println("事件已发布: " + event);
    }
}

验证

  • http://localhost:8083/test/person
  • http://localhost:8083/test/order

验证结果

✅✅✅ GenericEventListener 已被 Spring 加载!
2026-07-15 09:38:16.252 [main] [] INFO  org.apache.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-8083"]
2026-07-15 09:38:16.269 [main] [] INFO  org.springframework.boot.tomcat.TomcatWebServer - Tomcat started on port 8083 (http) with context path '/'
2026-07-15 09:38:16.272 [main] [] INFO  com.jysemel.spring.boot.Main - Started Main in 1.287 seconds (process running for 1.831)
2026-07-15 09:38:20.001 [http-nio-8083-exec-1] [] INFO  org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
2026-07-15 09:38:20.001 [http-nio-8083-exec-1] [] INFO  org.springframework.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
2026-07-15 09:38:20.003 [http-nio-8083-exec-1] [] INFO  org.springframework.web.servlet.DispatcherServlet - Completed initialization in 2 ms
2026-07-15 09:38:20.063 [event-async-1] [] INFO  com.jysemel.spring.boot.study.listener.GenericEventListener - 【Order监听器】操作: UPDATE, 数据: orderId=ORD-2026-001, amount=299.99
🔥🔥🔥【兜底原始类型】成功捕获事件,数据为: com.jysemel.spring.boot.study.event.Order@7bb383b
事件已发布: GenericEvent(data=com.jysemel.spring.boot.study.event.Order@7bb383b, operation=UPDATE)
🔥🔥🔥【兜底原始类型】成功捕获事件,数据为: com.jysemel.spring.boot.study.event.Person@36cdc7b7
事件已发布: GenericEvent(data=com.jysemel.spring.boot.study.event.Person@36cdc7b7, operation=ADD)
2026-07-15 09:38:25.396 [event-async-4] [] INFO  com.jysemel.spring.boot.study.listener.GenericEventListener - 【Person监听器】操作: ADD, 数据: name=张三, age=25
最近更新: 2026/7/16 15:24
Contributors: kcnf
Prev
spring event顺序和条件