动态设置JPA持久性属性

时间:2012-07-27 20:35:07

标签: java hibernate jpa jpa-2.0

假设我有以下persistence.xml和连接url,user&密码都是硬编码的。

以下是Hibernate 3.2。对于Hibernate 3.5 ++,我们必须将“hibernate.connection”更改为“javax.persistence”。但是,无论文字“hibernate.connection”或“javax.persistence”如何,我都要问这个问题。

<persistence-unit name="obamacare" transaction-type="RESOURCE_LOCAL">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>
  <exclude-unlisted-classes>false</exclude-unlisted-classes>
  <properties>
    <property name="hibernate.archive.autodetection" value="class, hbm"/>
    <property name="hibernate.connection.driver_class" value="oracle.jdbc.driver.OracleDriver"/>
    <property name="hibernate.connection.url" value="blah blah blah"/>
    <property name="hibernate.connection.username" value="careuser"/>
    <property name="hibernate.connection.password" value="carepass"/>
    <property name="hibernate.dialect" value="org.hibernate.dialect.OracleDialect"/>
    <property name="hibernate.show_sql" value="true"/>
  </properties>
  </persistence-unit>
</persistence>

但是,我们需要设置网址,用户和网址。密码动态。有一个提议的认证服务器,它服务于网址,用户和用户。密码。因此,我们不需要单独配置使用某种形式的jdbc,hibernate或JPA的无数webapp。除了不想在可见文本文件上存储/管理密码的安全问题。

就JPA而言,如何动态设置这些JPA属性?我正在寻求两套答案:

  1. 对于独立于JPA供应商的解决方案(toplink,eclipselink,hibernate等) - 是否有任何JPA功能可以让我动态设置这三个属性?

  2. 如果我被允许完全依赖Hibernate,除了可能的JPA唯一途径之外,有没有办法在不涉及Spring框架的情况下实现这一目标(这似乎是一个巨大的怪物,触手遍布各处)? / p>

  3. 如果你还希望在JNDI上投入两美分/ quids / rupe以及如何使用它来替换persistence.xml属性的功能,我会很高兴。但是,这不是问题的优先事项。

2 个答案:

答案 0 :(得分:7)

这取决于你如何引导你的EntityManagerFactory。 2个规范定义的方法每个允许您传入值的java.util.Map。这些值应该优先于持久性单元中定义的值。

在“SE方法”中没有问题,因为引导过程通常由您的应用程序控制:javax.persistence.Persistence#createEntityManagerFactory(String puName, Map config。现在你可能有问题,如果其他东西(ahem,Spring)为你“管理”EMF ......

在“EE方法”中,我不了解一种良好的全球方法。这个值映射仍然存在于引导中,但问题是EE容器是调用此方法的容器。

在任何一种情况下都可以使用一种特定于Hibernate的方法是使用配置变量替换。因此,在您的持久性单元中,您使用${some.key}定义用户名或密码,Hibernate将替换为您的用户名或密码。这是否真的有效取决于你最终想要如何设置这些值; Hibernate仍然需要访问名为some.key的配置值才能使其工作......

另一种“全局方法”......引导EMF的“EE方法”是容器实例化javax.persistence.spi.PersistenceProvider并调用其javax.persistence.spi.PersistenceProvider #createContainerEntityManagerFactory。 createContainerEntityManagerFactory在这里有一个有趣的签名。本质上它传递的是javax.persistence.spi.PersistenceUnitInfo,它是解析的持久性单元的对象表示以及其他一些东西。一个选项是使用这种方法来引导并传入一个构建你自己的javax.persistence.spi.PersistenceUnitInfo实例。 javax.persistence.spi.PersistenceProvider是一个接口。要实例化它,您需要知道要使用的提供程序和FQN到它们的impl。但这通常不是问题,因为这些都是众所周知的。

您特别询问JDBC连接创建/池。你有其他选择。您可以让您的“凭证服务”创建DataSources,而您的JPA提供程序只需使用该DataSource。所有JPA提供程序都支持通过JNDI查找定位DataSource。在“EE bootstrapping”中,提供者也可以通过PersistenceUnitInfo#getJtaDataSource和/或PersistenceUnitInfo#getNonJtaDataSource传递DataSource。 Hibernate交替接受DataSource实例来代替典型的DataSource JNDI名称设置。如果您不想使用DataSource(出于某些奇怪的原因),Hibernate特定的替代方法是自己实现Hibernate的ConnectionProvider契约,这是Hibernate在需要时用来获取和释放JDBC连接的契约(接口)。实现ConnectionProvider,您可以以任何您想要的方式配置底层连接。

很多选择:)

答案 1 :(得分:3)

对于第二个问题,我可以提供仅限Hibernate的解决方案。

package dev.stackoverflow;

import java.util.Properties;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class DynamicHibernateSessionFactory {
    public Session setProperties(final String provider,
                                 final Boolean excludeUnlisted,
                                 final Properties properties) {
        properties.setProperty("provider", provider);
        properties.setProperty("exclude-unlisted-classes", excludeUnlisted.toString());
        Configuration configuration = new Configuration();
        configuration.setProperties(properties);
        SessionFactory sessionFactory = configuration.configure().buildSessionFactory();
        return sessionFactory.openSession();
    }
}
相关问题