我正在努力使用休眠模式在基于Spring的应用程序中启用 Multi-Tenancy 。我创建了CurrentTenantIdentifierResolver
的自定义实现,并覆盖了resolveCurrentTenantIdentifier()
方法以确定租户标识符。当我提供硬编码的租户标识符时,该应用程序运行良好。
但是随后提出了一个要求,即根据请求标头中的值从数据库默认架构的表中获取租户标识符。我在很多地方都进行了搜索,做了一些命中和尝试,但收效甚微。
任何帮助,将不胜感激。请让我知道我需要提供什么所有信息以更好地了解问题情况。
CustomTenantIdentifierResolver.java
public class CustomTenantIdentifierResolver implements CurrentTenantIdentifierResolver {
public static final String DEFAULT_TENANT_SCHEMA = "public";
@Override
public String resolveCurrentTenantIdentifier() {
try {
Provider<TenantRequestContext> tenantProvider = SpringContext
.getBean(Provider.class);
if (tenantProvider == null) {
return DEFAULT_TENANT_SCHEMA;
} else {
TenantRequestContext tenantRequestContext = tenantProvider
.get();
String tenantId = tenantRequestContext.getTenantIdValue();
String tenantSchema = tenantRequestContext.getTenantSchema(tenantId);
return tenantSchema;
}
} catch (Exception ex) {
return DEFAULT_TENANT_SCHEMA;
}
// return "myschema";
}
@Override
public boolean validateExistingCurrentSessions() {
return true;
}
}
TenantRequestContextImpl.java
@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class TenantRequestContextImpl implements TenantRequestContext{
@Autowired
private TenantReadService tenantReadService;
@Override
public String getTenantIdValue() {
String tenantId =((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes())
.getRequest().getHeader("tenantId");
return tenantId;
}
@Override
public String getTenantSchema(String tenantId) {
Tenant tenant = tenantReadService.findById(Integer.parseInt(tenantId));
return tenant.getTenantSchemaName();
}
}
TenantReadServiceImpl.java
@Repository
public class TenantReadServiceImpl implements TenantReadService {
@Autowired
private SessionFactory defaultSessionFactory;
public TenantReadServiceImpl() {
}
public TenantReadServiceImpl(SessionFactory defaultSessionFactory) {
this.defaultSessionFactory = defaultSessionFactory;
}
@Override
@Transactional
public Tenant findById(Integer tenantId) {
String hql = "from Tenant where id=" + tenantId;
Query query = defaultSessionFactory.getCurrentSession().createQuery(hql);
Tenant tenant = (Tenant) query.uniqueResult();
defaultSessionFactory.getCurrentSession().clear();
return tenant;
}
}
MultitenancyPlatformConfig.java
@Configuration
@EnableTransactionManagement
@ComponentScan("com.mypackage")
public class MultitenancyPlatformConfig {
@Bean(name="defaultDataSource")
public DataSource dataSource() {
final JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
DataSource dataSource = dsLookup.getDataSource(java:comp/env/jdbc/myDataSource);
return dataSource;
}
@Autowired
@Bean(name = "defaultSessionFactory")
public SessionFactory getSessionFactory(DataSource defaultDataSource) {
LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(
defaultDataSource);
sessionBuilder.addAnnotatedClasses(Tenant.class);
sessionBuilder.addProperties(hibProperties());
return sessionBuilder.buildSessionFactory();
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put("hibernate.format_sql",
"true");
properties.put("hibernate.dialect",
"org.hibernate.dialect.PostgreSQLDialect");
properties.put("hibernate.default_schema", "public");
return properties;
}
@Autowired
@Bean(name = "tenantReadService")
public TenantReadService getTenantReadService(SessionFactory defaultSessionFactory) {
return new TenantReadServiceImpl(defaultSessionFactory);
}
}
MyPlatformConfig.java
@Configuration
@EnableTransactionManagement
@ComponentScan("com.mypackage")
@EnableJpaRepositories("com.mypackage.repository")
public class MyPlatformConfig {
@Bean
public DataSource dataSource() {
final JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
DataSource dataSource = dsLookup.getDataSource("java:comp/env/jdbc/ihubDataSource");
return dataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(false);
vendorAdapter.setDatabase(Database.POSTGRESQL);
vendorAdapter.setDatabasePlatform("org.postgresql.Driver");
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.mypackage.entity");
factory.setJpaProperties(hibProperties());
return factory;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect","org.hibernate.dialect.PostgreSQLDialect");
properties.put("hibernate.format_sql","true");
properties.put("hibernate.tenant_identifier_resolver"," com.mypackage.tenantresolvers.CustomTenantIdentifierResolver");
properties.put("hibernate.multi_tenant_connection_provider", "com.mypackage.connectionproviders.MultiTenantConnectionProviderImpl");
properties.put("hibernate.multiTenancy", "SCHEMA");
return properties;
}
@Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
}
最佳答案
这是解决问题的方法:
resolveCurrentTenantIdentifier
中,只需从ThreadLocal返回值即可。