针对多租户应用程序的Spring和Hibernate急切初始化问题

时间:2014-07-09 16:32:04

标签: spring hibernate multi-tenant spring-orm

我们使用Spring 3.2.0和Hibernate 4.1.12开发Web应用程序。

该应用程序支持"基于数据源"多租户,意味着每个应用程序租户都使用专用数据源。

数据源JNDI名称在运行时根据请求应用程序的用户的名称解析(用户名告知必须使用哪个租户)。解决方案是通过实现Hibernate的org.hibernate.service.jdbc.connections.spi.ConnectionProvider接口完成的。

Spring配置(摘录)是:

<bean id="tenantHibernateSessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">

    <property name="packagesToScan">
        <list>
            <value>com.foo.bar.model</value>
        </list>
    </property>

    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.show_sql">false</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.DB2Dialect</prop>
            <prop key="hibernate.format_sql">false</prop>
            <prop key="hibernate.connection.autocommit">true</prop>
            <prop key="hibernate.connection.provider_class">com.foo.bar.dao.hibernate.CustomConnectionProvider</prop>
        </props>
    </property>
</bean>

在应用程序部署期间,Spring初始化应用程序和org.springframework.orm.hibernate4.LocalSessionFactoryBean实例。这最终会执行数据库访问。此数据库访问失败,因为我们的CustomConnectionProvider返回空连接。我们返回一个空连接,因为在部署时,我们无法识别当前的租户。在应用程序部署期间访问数据库毫无意义。我们得到的堆栈跟踪是:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tenantHibernateSessionFactory' defined in file [D:\Work\Java\apache-tomcat-6.0.39\webapps\ams-gate\WEB-INF\classes\META-INF\spring\persistence.xml]: Invocation of init method failed; nested exception is java.lang.NullPointerException
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1486)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:524)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:873)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:815)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:730)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:558)
    ... 129 more
Caused by: java.lang.NullPointerException
    at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:119)
    at org.hibernate.service.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:75)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:159)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:131)
    at org.hibernate.cfg.SettingsFactory.buildSettings(SettingsFactory.java:77)
    at org.hibernate.cfg.Configuration.buildSettingsInternal(Configuration.java:2287)
    at org.hibernate.cfg.Configuration.buildSettings(Configuration.java:2283)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1752)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1792)
    at org.springframework.orm.hibernate4.LocalSessionFactoryBuilder.buildSessionFactory(LocalSessionFactoryBuilder.java:242)
    at org.springframework.orm.hibernate4.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:372)
    at org.springframework.orm.hibernate4.LocalSessionFactoryBean.afterPropertiesSet(LocalSessionFactoryBean.java:357)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1545)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1483)
    ... 139 more

我查看了Hibernate源代码,发现了一个可能在部署期间禁用数据库访问的属性:

<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>

但它似乎不适用于此。

更新1 :此Hibernate属性会在应用程序部署期间禁用数据库访问。但是根据Hibernate 4.1.12中的org.hibernate.engine.jdbc.internal.JdbcServicesImpl,这个属性是一个未记录的临时魔术值。

是否建议在部署期间禁用数据库访问以正确支持多租户?

感谢您的时间

0 个答案:

没有答案