在MultiTenant连接提供程序中选择DataSource时出现NullPointerException

时间:2017-02-25 19:03:05

标签: java spring hibernate multi-tenant

我重新利用现有的hibernate-spring项目并升级到Hibernate 4和Spring 4,并使用多租户添加了多个数据源。应用程序启动正常,使用MultiTenantDataSourceLookup类读入数据源。设置新租户时,租户已解决,但之后我在MultiTenantConnectionProviderImpl的第41行获得了nullpointerexception(请参阅注释行)。如果有帮助,我也使用GenericHibernateDAO。我可以按要求发布该代码。我是春天的新手,所以问题可能很简单。但是,如果需要更多代码来帮助我,我将很乐意分享更多内容,因为我自己进行了故障排除和研究。任何帮助将不胜感激。谢谢。以下是完整堆栈跟踪:http://pastebin.com/LjyhTwvY

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;
    }   
}

CurrentTenantIdentifierResolverImpl.java

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>

输出

Tenant resolved: customer1

Feb 25, 2017 1:34:31 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [studentHibernateServlet] in context with path [/StudentEnrollmentWithSpring] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException
at com.github.elizabetht.util.MultiTenantConnectionProviderImpl.selectDataSource(MultiTenantConnectionProviderImpl.java:41)
at org.hibernate.engine.jdbc.connections.spi.AbstractDataSourceBasedMultiTenantConnectionProviderImpl.getConnection(AbstractDataSourceBasedMultiTenantConnectionProviderImpl.java:52)
at org.hibernate.internal.AbstractSessionImpl$ContextualJdbcConnectionAccess.obtainConnection(AbstractSessionImpl.java:423)
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:228)

1 个答案:

答案 0 :(得分:0)

我将我的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>