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 |
关联关系更新后 |
⚠️ 注意:
BeforeLinkSave
和AfterLinkSave
用于处理资源之间的关联操作,比如通过 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