Hibernate 6.x中如何全局定义Filter并复用?附代码示例
解决Hibernate 6.x中全局过滤器定义与复用问题
Hibernate 6.x强化了过滤器定义的唯一性校验,不允许多个@FilterDef使用相同名称,因此之前在多个实体类重复定义同名过滤器的方式会触发Multiple @FilterDef annotation defines a filter name报错。以下是两种全局统一定义并复用过滤器的方案:
方案1:包级注解全局定义
在实体类所在的包下创建package-info.java文件,在此处全局注册过滤器定义,所有实体类只需通过@Filter引用即可。
1.1 创建包级注解文件
@FilterDef( name = "tenantFilter", // 全局唯一的过滤器名称 parameters = @ParamDef(name = "tenantId", type = "long") ) package com.yourproject.entity; import org.hibernate.annotations.FilterDef; import org.hibernate.annotations.ParamDef;
1.2 在实体类中引用过滤器
import jakarta.persistence.Entity; import org.hibernate.annotations.Filter; @Entity @Filter(name = "tenantFilter", condition = "tenant_id = :tenantId") public class Order { // 实体字段、构造方法及其他逻辑 } @Entity @Filter(name = "tenantFilter", condition = "tenant_id = :tenantId") public class Product { // 实体字段、构造方法及其他逻辑 }
方案2:编程式全局注册
如果需要动态配置过滤器,可通过自定义Hibernate配置类注册全局过滤器,无需在包或实体上添加@FilterDef。
2.1 编写Hibernate配置类
import org.hibernate.boot.MetadataBuilder; import org.hibernate.boot.spi.MetadataBuilderContributor; import org.hibernate.annotations.FilterDef; import org.hibernate.annotations.ParamDef; import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.Map; @Configuration public class HibernateGlobalFilterConfig { @Bean public HibernatePropertiesCustomizer hibernatePropertiesCustomizer() { return hibernateProperties -> { hibernateProperties.put("hibernate.metadata_builder_contributor", (MetadataBuilderContributor) metadataBuilder -> { // 注册全局过滤器 metadataBuilder.applyFilterDef( FilterDef.create( "tenantFilter", Map.of("tenantId", ParamDef.create("long")) ) ); }); }; } }
2.2 实体类中引用过滤器
import jakarta.persistence.Entity; import org.hibernate.annotations.Filter; @Entity @Filter(name = "tenantFilter", condition = "tenant_id = :tenantId") public class User { // 实体字段、构造方法及其他逻辑 }
启用过滤器示例
在业务逻辑中通过Session开启过滤器并设置参数:
import jakarta.persistence.EntityManager; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class TenantService { private final EntityManager entityManager; public TenantService(EntityManager entityManager) { this.entityManager = entityManager; } @Transactional public void activateTenantFilter(Long tenantId) { entityManager.unwrap(org.hibernate.Session.class) .enableFilter("tenantFilter") .setParameter("tenantId", tenantId); } }
注意事项
- 确保过滤器名称全局唯一,禁止在任何实体类上重复定义
@FilterDef - 不同实体可根据自身表结构设置不同的
condition条件,但必须引用同一个全局过滤器名称 - Hibernate 6.x对
@FilterDef的作用域做了严格限制,重复同名定义会触发校验报错
内容的提问来源于stack exchange,提问作者Aditya Srivastava
相关产品推荐
相关产品推荐

