1. 概述
本文将探讨在 Hibernate 的 ORM 实现中拦截操作的多种方式。Hibernate 拦截器是监听核心操作(如保存、更新、删除)的强大工具,通过回调机制实现应用与 Hibernate 会话的通信。
2. 定义 Hibernate 拦截器
Hibernate 拦截器是一个接口,允许我们响应 Hibernate 内部的特定事件。这些拦截器作为回调注册,提供 Hibernate 会话与应用程序之间的通信桥梁。通过回调,应用可以拦截 Hibernate 的核心操作。
定义拦截器有两种方式:
- 实现
org.hibernate.Interceptor
接口 - 继承
org.hibernate.EmptyInterceptor
类
2.1. 实现 Interceptor 接口
实现 org.hibernate.Interceptor
需要重写约 14 个方法,包括 onLoad
、onSave
、onDelete
、findDirty
等。
⚠️ 注意:实现类必须可序列化(implements java.io.Serializable
)。
典型示例:
public class CustomInterceptorImpl implements Interceptor, Serializable {
@Override
public boolean onLoad(Object entity, Serializable id,
Object[] state, String[] propertyNames, Type[] types)
throws CallbackException {
// ...
return false;
}
// ...
@Override
public String onPrepareStatement(String sql) {
// ...
return sql;
}
}
如果没有特殊需求,**强烈建议继承 EmptyInterceptor
**,只需重写必要方法。
2.2. 继承 EmptyInterceptor
继承 org.hibernate.EmptyInterceptor
是更简单的定义方式。只需重写与目标操作相关的方法。
例如定义 CustomInterceptor
:
public class CustomInterceptor extends EmptyInterceptor {
}
若需拦截保存操作,重写 onSave
方法:
@Override
public boolean onSave(Object entity, Serializable id,
Object[] state, String[] propertyNames, Type[] types) {
if (entity instanceof User) {
logger.info(((User) entity).toString());
}
return super.onSave(entity, id, state, propertyNames, types);
}
✅ 最佳实践:通过 super.onSave()
传播事件,避免直接返回 true/false
。
另一个实用场景是数据库操作审计。使用 onFlushDirty()
监听实体变更:
@Override
public boolean onFlushDirty(Object entity, Serializable id,
Object[] currentState, Object [] previousState,
String[] propertyNames, Type[] types) {
if (entity instanceof User) {
((User) entity).setLastModified(new Date());
logger.info(((User) entity).toString());
}
return super.onFlushDirty(entity, id, currentState,
previousState, propertyNames, types);
}
类似地,删除和加载操作可通过 onDelete
和 onLoad
拦截。
3. 注册拦截器
Hibernate 拦截器可分为 会话作用域(Session-scoped) 和 会话工厂作用域(SessionFactory-scoped) 两种。
3.1. 会话作用域拦截器
会话作用域拦截器绑定到特定会话,在创建会话时指定:
public static Session getSessionWithInterceptor(Interceptor interceptor)
throws IOException {
return getSessionFactory().withOptions()
.interceptor(interceptor).openSession();
}
3.2. 会话工厂作用域拦截器
会话工厂作用域拦截器在构建 SessionFactory
前注册:
ServiceRegistry serviceRegistry = configureServiceRegistry();
SessionFactory sessionFactory = getSessionFactoryBuilder(serviceRegistry)
.applyInterceptor(new CustomInterceptor())
.build();
⚠️ 重要提示:
- 会话工厂作用域拦截器应用于所有会话
- 禁止存储会话特定状态(多线程并发访问)
- 需确保线程安全,可通过配置实现:
或 XML 配置:hibernate.current_session_context_class=org.hibernate.context.internal.ThreadLocalSessionContext
<property name="hibernate.current_session_context_class"> org.hibernate.context.internal.ThreadLocalSessionContext </property>
- 必须实现
Serializable
接口的readResolve
方法保证序列化安全
4. 总结
我们学习了如何定义和注册 Hibernate 拦截器(会话作用域/会话工厂作用域)。无论哪种方式,必须确保拦截器可序列化(尤其当会话需要序列化时)。
替代方案包括:
- Hibernate 事件(Events)
- JPA 回调(Callbacks)
完整源码请查阅 GitHub 仓库