1. 概述

本文将探讨在 Hibernate 的 ORM 实现中拦截操作的多种方式。Hibernate 拦截器是监听核心操作(如保存、更新、删除)的强大工具,通过回调机制实现应用与 Hibernate 会话的通信。

2. 定义 Hibernate 拦截器

Hibernate 拦截器是一个接口,允许我们响应 Hibernate 内部的特定事件。这些拦截器作为回调注册,提供 Hibernate 会话与应用程序之间的通信桥梁。通过回调,应用可以拦截 Hibernate 的核心操作。

定义拦截器有两种方式:

  1. 实现 org.hibernate.Interceptor 接口
  2. 继承 org.hibernate.EmptyInterceptor

2.1. 实现 Interceptor 接口

实现 org.hibernate.Interceptor 需要重写约 14 个方法,包括 onLoadonSaveonDeletefindDirty 等。

⚠️ 注意:实现类必须可序列化(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);
}

类似地,删除和加载操作可通过 onDeleteonLoad 拦截。

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();

⚠️ 重要提示:

  • 会话工厂作用域拦截器应用于所有会话
  • 禁止存储会话特定状态(多线程并发访问)
  • 需确保线程安全,可通过配置实现:
    hibernate.current_session_context_class=org.hibernate.context.internal.ThreadLocalSessionContext
    
    或 XML 配置:
    <property name="hibernate.current_session_context_class">
        org.hibernate.context.internal.ThreadLocalSessionContext
    </property>
    
  • 必须实现 Serializable 接口的 readResolve 方法保证序列化安全

4. 总结

我们学习了如何定义和注册 Hibernate 拦截器(会话作用域/会话工厂作用域)。无论哪种方式,必须确保拦截器可序列化(尤其当会话需要序列化时)。

替代方案包括:

  • Hibernate 事件(Events)
  • JPA 回调(Callbacks)

完整源码请查阅 GitHub 仓库


原始标题:Hibernate Interceptors

« 上一篇: Java 内置注解详解
» 下一篇: OrientDB Java API 指南