无需反射指定hibernate.multi_tenant_connection_provider的实现方案
问题解决方案
你完全可以跳过属性文件配置类路径、Hibernate反射实例化的流程,手动注册自行创建的实例,具体实现步骤如下:
1. 移除属性文件中的对应配置
删掉原来的两行反射加载配置:
hibernate.multi_tenant_connection_provider: com.app.MapMultiTenantConnectionProvider hibernate.tenant_identifier_resolver: com.app.MultiTenantCurrentTenantIdentifierResolver
2. 改造组件类增加带参构造
修改MapMultiTenantConnectionProvider类,用成员变量接收配置,替代静态变量引用:
public class MapMultiTenantConnectionProvider extends AbstractMultiTenantConnectionProvider { private static Logger log = LoggerFactory.getLogger(MapMultiTenantConnectionProvider.class); private Map<String, ConnectionProvider> connectionProviderMap = new HashMap<>(); // 配置改为成员变量,不需要静态存储 private final MyConfig config; // 新增带参构造接收外部传入的配置 public MapMultiTenantConnectionProvider(MyConfig config) { this.config = config; } @Override protected ConnectionProvider getAnyConnectionProvider() { return getConnectionProviderForTenant("chorus"); } @Override protected ConnectionProvider selectConnectionProvider(final String tenantIdentifier) { return getConnectionProviderForTenant(tenantIdentifier); } private ConnectionProvider getConnectionProviderForTenant(final String tenantId) { final ConnectionProvider connectionProvider; if (!connectionProviderMap.containsKey(tenantId)) { final Properties properties = new Properties(); properties.setProperty("hibernate.connection.url", config.connectionUrl); properties.setProperty("hibernate.connection.username", config.username); properties.setProperty("hibernate.connection.password", config.password); properties.setProperty("hibernate.dialect", config.databaseConfig.getHibernateDialect()); final DriverManagerConnectionProviderImpl newConnectionProvider = new DriverManagerConnectionProviderImpl(); newConnectionProvider.configure(properties); this.connectionProviderMap.put(tenantId, newConnectionProvider); connectionProvider = newConnectionProvider; } else { connectionProvider = connectionProviderMap.get(tenantId); } return connectionProvider; } }
租户ID解析器MultiTenantCurrentTenantIdentifierResolver也可以用同样方式增加带参构造,传入你需要的用户上下文、请求持有类等动态依赖。
3. 构建SessionFactory时手动注册实例
在你初始化Hibernate SessionFactory的逻辑中,手动实例化两个组件后直接注册到服务注册表:
// 此处已经拿到DropWizard初始化好的configuration对象 MyConfig config = ...; // 自行实例化两个组件,传入所有需要的依赖 MapMultiTenantConnectionProvider connectionProvider = new MapMultiTenantConnectionProvider(config); MultiTenantCurrentTenantIdentifierResolver tenantResolver = new MultiTenantCurrentTenantIdentifierResolver(用户上下文依赖); // 构建服务注册表时手动注册服务 StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() .applySettings(其他Hibernate常规配置) // 注册自定义的多租户连接提供器实例 .addService(MultiTenantConnectionProvider.class, connectionProvider) // 注册自定义的租户ID解析器实例 .addService(CurrentTenantIdentifierResolver.class, tenantResolver) .build(); // 后续正常构建SessionFactory即可 SessionFactory sessionFactory = new MetadataSources(serviceRegistry) .addAnnotatedClass(你的实体类.class) .buildMetadata() .buildSessionFactory();
补充说明
该方式完全绕过了Hibernate的反射实例化逻辑,你可以完全控制两个组件的生命周期和依赖注入,不需要再用静态变量存储配置。如果是配合Spring等DI容器使用的场景,也可以把这两个组件交给容器管理,注入所有依赖后再注册到Hibernate服务注册表即可。
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

