Java 在多租户连接提供程序中选择数据源时出现NullPointerException
我重新调整了现有hibernate spring项目的用途,升级到hibernate 4和spring 4,并使用多租户添加了多个数据源。应用程序启动正常,正在使用MultiTenantDataSourceLookup类读入数据源。设置新租户时,租户已解析,但随后我在MultiTenantConnectionProviderImpl的第41行获得nullpointerexception(请参阅第行的注释)。如果有帮助的话,我也在使用generichbernatedao。我可以根据要求发布代码。我刚接触spring,所以问题可能很简单。但是,如果需要更多的代码来帮助我,我会很乐意在自己解决问题和研究问题时分享更多。任何帮助都将不胜感激。谢谢以下是完整的堆栈跟踪:Java 在多租户连接提供程序中选择数据源时出现NullPointerException,java,spring,hibernate,multi-tenant,Java,Spring,Hibernate,Multi Tenant,我重新调整了现有hibernate spring项目的用途,升级到hibernate 4和spring 4,并使用多租户添加了多个数据源。应用程序启动正常,正在使用MultiTenantDataSourceLookup类读入数据源。设置新租户时,租户已解析,但随后我在MultiTenantConnectionProviderImpl的第41行获得nullpointerexception(请参阅第行的注释)。如果有帮助的话,我也在使用generichbernatedao。我可以根据要求发布代码。我
MultiTenantConnectionProviderImpl.java
public class MultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl
{
@Autowired
private DataSource defaultDataSource;
@Autowired
private DataSourceLookup dataSourceLookup;
/**
* Select datasources in situations where not tenantId is used (e.g. startup processing).
*/
@Override
protected DataSource selectAnyDataSource() {
return defaultDataSource;
}
/**
* Obtains a DataSource based on tenantId
*/
@Override
protected DataSource selectDataSource(String tenantIdentifier) {
//Below is line 41 where the nullpointerexeption is occurring
DataSource ds = dataSourceLookup.getDataSource(tenantIdentifier);
return ds;
}
}
public class CurrentTenantIdentifierResolverImpl implements CurrentTenantIdentifierResolver {
private static final String KEY_TENANTID_SESSION = "hibernate.tenant_identifier_resolver";
private static final String DEFAULT_TENANTID = "customer1";
public String resolveCurrentTenantIdentifier() {
String tenant = resolveTenantByHttpSession();
System.out.println("Tenant resolved: " + tenant);
return tenant;
}
/**
* Get tenantId in the session attribute KEY_TENANTID_SESSION
* @return TenantId on KEY_TENANTID_SESSION
*/
public String resolveTenantByHttpSession()
{
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//If session attribute exists returns tenantId saved on the session
if(attr != null){
HttpSession session = attr.getRequest().getSession(false); // true == allow create
if(session != null){
String tenant = (String) session.getAttribute(KEY_TENANTID_SESSION);
if(tenant != null){
return tenant;
}
}
}
//otherwise return default tenant
return DEFAULT_TENANTID;
}
public boolean validateExistingCurrentSessions() {
return true;
}
}
CurrentTenantIdentifierResolverImpl.java
public class MultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl
{
@Autowired
private DataSource defaultDataSource;
@Autowired
private DataSourceLookup dataSourceLookup;
/**
* Select datasources in situations where not tenantId is used (e.g. startup processing).
*/
@Override
protected DataSource selectAnyDataSource() {
return defaultDataSource;
}
/**
* Obtains a DataSource based on tenantId
*/
@Override
protected DataSource selectDataSource(String tenantIdentifier) {
//Below is line 41 where the nullpointerexeption is occurring
DataSource ds = dataSourceLookup.getDataSource(tenantIdentifier);
return ds;
}
}
public class CurrentTenantIdentifierResolverImpl implements CurrentTenantIdentifierResolver {
private static final String KEY_TENANTID_SESSION = "hibernate.tenant_identifier_resolver";
private static final String DEFAULT_TENANTID = "customer1";
public String resolveCurrentTenantIdentifier() {
String tenant = resolveTenantByHttpSession();
System.out.println("Tenant resolved: " + tenant);
return tenant;
}
/**
* Get tenantId in the session attribute KEY_TENANTID_SESSION
* @return TenantId on KEY_TENANTID_SESSION
*/
public String resolveTenantByHttpSession()
{
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//If session attribute exists returns tenantId saved on the session
if(attr != null){
HttpSession session = attr.getRequest().getSession(false); // true == allow create
if(session != null){
String tenant = (String) session.getAttribute(KEY_TENANTID_SESSION);
if(tenant != null){
return tenant;
}
}
}
//otherwise return default tenant
return DEFAULT_TENANTID;
}
public boolean validateExistingCurrentSessions() {
return true;
}
}
Context.xml
<context:annotation-config />
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
<bean id="multitenancyConnectionProvider"
class="com.github.elizabetht.util.MultiTenantConnectionProviderImpl"/>
<bean id="dataSourceLookup"
class="com.github.elizabetht.util.MultiTenantDataSourceLookup"/>
<bean id="tenantResolver"
class="com.github.elizabetht.util.CurrentTenantIdentifierResolverImpl"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="packagesToScan">
<list>
<value>com.github.elizabetht.model</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
<prop key="hibernate.jdbc.lob.non_contextual_creation">true</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.multiTenancy">DATABASE</prop>
<prop key="hibernate.multi_tenant_connection_provider">com.github.elizabetht.util.MultiTenantConnectionProviderImpl</prop>
<prop key="hibernate.tenant_identifier_resolver">com.github.elizabetht.util.CurrentTenantIdentifierResolverImpl</prop>
</props>
</property>
</bean>
<bean id="defaultDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/studentEnrollment" />
<property name="username" value="springy" />
<property name="password" value="pass" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<property name="autodetectDataSource" value="false"/>
</bean>
我将hibernate属性更改为以下内容,现在一切正常:
<property name="hibernateProperties">
<map>
<entry key="hibernate.multi_tenant_connection_provider" value-ref="multitenancyConnectionProvider"/>
<entry key="hibernate.tenant_identifier_resolver" value-ref="tenantResolver"/>
<entry key="hibernate.multiTenancy" value="DATABASE"/>
</map>
</property>
显然dataSourceLookup
为空,根据给定的配置,我猜Hibernate已经实例化了自己的MultiTenantConnectionProviderImpl
实例,而不是通过Spring注入它。删除了最后一条注释,因为我错了,对此表示抱歉。我明白你在说什么,试图解决它。。。