1. 概述

在使用 Spring Data REST 时,我们对实体(Entity)的增删改操作都会触发对应的事件——比如创建、保存、删除。这些事件默认由框架自动处理,但有时候我们需要在这些操作前后插入自定义逻辑,比如记录日志、校验数据、发送通知等。

最直接的方式是使用 Spring 的 ApplicationListener 来监听这些事件。但问题来了:ApplicationListener 是全局的,它无法区分不同类型的实体事件,所有事件都得自己判断类型,写起来啰嗦还容易踩坑 ❌。

更好的选择是使用 @RepositoryEventHandler ——它能按实体类型过滤事件,让你的事件处理代码更清晰、更专注 ✅。简单粗暴地说,就是“谁的事件,谁来处理”。

2. 编写注解式事件处理器

ApplicationListener 是“通吃”所有事件,而 @RepositoryEventHandler 可以做到 按领域类型(domain type)精准拦截,这才是我们想要的。

2.1 基本用法:为特定实体绑定处理器

只需要在一个普通类上加上 @RepositoryEventHandler(实体类.class),Spring 就会把这个类当作该实体的专属事件处理器。

比如我们为 Author 实体写一个处理器:

@RepositoryEventHandler(Author.class) 
public class AuthorEventHandler {
    Logger logger = Logger.getLogger("Class AuthorEventHandler");
    
    @HandleBeforeCreate
    public void handleAuthorBeforeCreate(Author author){
        logger.info("Inside Author Before Create....");
        String name = author.getName();
    }

    @HandleAfterCreate
    public void handleAuthorAfterCreate(Author author){
        logger.info("Inside Author After Create ....");
        String name = author.getName();
    }

    @HandleBeforeDelete
    public void handleAuthorBeforeDelete(Author author){
        logger.info("Inside Author Before Delete ....");
        String name = author.getName();
    }

    @HandleAfterDelete
    public void handleAuthorAfterDelete(Author author){
        logger.info("Inside Author After Delete ....");
        String name = author.getName();
    }
}

✅ 只要对 Author 执行创建或删除操作,对应的方法就会自动触发。
✅ 方法名随意,只要参数是 Author 类型 + 使用正确的 @HandleXxx 注解即可。
⚠️ 注意:方法必须是 public,否则不会被识别。

2.2 支持的事件类型

Spring Data REST 提供了两类事件注解,分别对应操作前后:

✅ Before 事件(前置拦截)

注解 触发时机
@HandleBeforeCreate 实体创建前(POST)
@HandleBeforeSave 实体保存前(PUT/PATCH)
@HandleBeforeDelete 实体删除前(DELETE)
@HandleBeforeLinkSave 关联关系更新前(如 /books/1/authors

✅ After 事件(后置通知)

注解 触发时机
@HandleAfterCreate 实体创建后
@HandleAfterSave 实体保存后
@HandleAfterDelete 实体删除后
@HandleAfterLinkSave 关联关系更新后

⚠️ 注意:BeforeLinkSaveAfterLinkSave 用于处理资源之间的关联操作,比如通过 REST 接口建立书籍和作者的关系。

2.3 一个处理器处理多个实体

你也可以写一个“通用”处理器,处理多个实体的同类事件。只需要去掉 @RepositoryEventHandler 的类级别注解,或不指定具体类型:

@RepositoryEventHandler
public class BookEventHandler {

    @HandleBeforeCreate
    public void handleBookBeforeCreate(Book book){
        // 处理 Book 创建前逻辑
    }

    @HandleBeforeCreate
    public void handleAuthorBeforeCreate(Author author){
        // 处理 Author 创建前逻辑
    }
}

✅ Spring 会根据方法参数的类型自动匹配该方法应响应哪个实体的事件。
✅ 适合共性逻辑抽取,比如“所有实体创建前都打个日志”。

2.4 注册事件处理器

光写好处理器还不够,必须把它注册为 Spring Bean,否则框架根本找不到它。

通常我们在配置类中通过 @Bean 注册:

@Configuration
public class RepositoryConfiguration {
    
    public RepositoryConfiguration(){
        super();
    }

    @Bean
    AuthorEventHandler authorEventHandler() {
        return new AuthorEventHandler();
    }

    @Bean
    BookEventHandler bookEventHandler(){
        return new BookEventHandler();
    }
}

✅ 只要被 Spring 管理,@RepositoryEventHandler 才能生效。
✅ 推荐使用 Java Config 方式注册,清晰可控。

3. 总结

@RepositoryEventHandler 是 Spring Data REST 中处理持久层事件的优雅方案,相比 ApplicationListener

  • ✅ 更专注:按实体类型隔离逻辑,避免一堆 instanceof 判断
  • ✅ 更简洁:注解驱动,方法即处理器
  • ✅ 更灵活:支持前后置事件,覆盖 CRUD 全流程

适用于审计日志、权限校验、缓存同步、异步通知等场景。掌握它,能让你在不侵入业务代码的前提下,轻松扩展 REST 接口的行为。

完整示例代码可参考 GitHub:https://github.com/example/spring-data-rest-events-demo