2012-07-27 193 views
8

比方說,我有以下persistence.xml與連接url,用戶&密碼全部硬編碼。動態設置JPA持久性屬性

以下是針對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> 

然而,我們需要動態設置URL,用戶&密碼。有一個提議的認證服務器提供URL,用戶密碼爲&。因此,我們不需要單獨配置使用某種形式的jdbc,hibernate或JPA的大量webapps。除了不希望在可見文本文件上存儲/管理密碼的安全問題之外。

就JPA而言,如何動態設置這些JPA屬性?我尋求兩套答案:

  1. 一個解決方案,是獨立的JPA廠商(TopLink的,的EclipseLink,休眠等) - 是否有任何JPA的功能,將讓我動態設置這三個屬性?

  2. 如果我被允許完全依賴Hibernate,除了可能的JPA唯一途徑之外,是否有辦法在不涉及Spring框架的情況下實現這一點(這看起來像是一個巨大的怪物,觸手遍及整個地方)?

,如果你也想在兩分錢扔我就心花怒放/ quids在JNDI,以及如何我可以用它來代替的persistence.xml屬性的功能/盧比。但是,這不是問題的優先事項。

+1

大部分想要完成的事情都可以使用Spring輕鬆完成。我正在使用Spring幾周,我根本不後悔。春天似乎是一項很大的工作,但實際上很簡單。 – siebz0r 2012-07-28 13:39:23

回答

7

這取決於你如何引導你的EntityManagerFactory。這兩個規範定義的方法都允許您傳入值的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是一個接口。要實例化它,你需要知道你想要使用的提供者和他們的impl的FQN。但這通常不是問題,因爲這些都是衆所周知的。

您具體詢問JDBC連接創建/池。你在那裏有更多的選擇。您可以讓您的「憑證服務」創建DataSources,並且您的JPA提供者只需使用該DataSource。所有JPA提供者都支持通過JNDI查找來定位DataSources。在「EE bootstrapping」提供程序中,也可以通過PersistenceUnitInfo#getJtaDataSource和/或PersistenceUnitInfo#getNonJtaDataSource傳遞一個DataSource。 Hibernate會交替接受DataSource實例來代替典型的DataSource JNDI名稱設置。如果你不想使用DataSource(出於某種奇怪的原因),Hibernate特定的替代方案是自己實現Hibernate的ConnectionProvider契約,這是Hibernate在需要時用來獲取和釋放JDBC連接的契約(接口)。實現ConnectionProvider你可以用你想要的任何方式配置底層連接。

很多選項:)

+0

另一種「全局方法」......引導EMF的「EE方法」是實例化javax.persistence.spi.PersistenceProvider並調用其javax.persistence.spi.PersistenceProvider#createContainerEntityManagerFactory。 createContainerEntityManagerFactory在這裏有一個有趣的簽名。本質上,它傳遞了一個javax.persistence.spi.PersistenceUnitInfo,它是解析的持久性單元的對象表示加上一些其他的東西。 On選項將使用此方法來引導並傳入構造自我的javax.persistence.spi.PersistenceUnitInfo – 2012-07-27 23:16:33

+0

在最後的評論中,空間不足:) javax.persistence.spi.PersistenceProvider是一個接口。要實例化它,你需要知道你想要使用的提供者和他們的impl的FQN。但這通常不是問題,因爲這些都是衆所周知的。 – 2012-07-27 23:18:26

+0

史蒂夫,謝謝你的努力。有沒有可能將您的意見轉移到答案區域? $ {some.key}替換方法正是我所需要的。你可以讓我舉一個例子來說明如何在hibernate的persistence.xml中做到這一點。因爲我們的產品盒是jboss 4.x,所以我們必須使用hibernate 3.2而不是hibernate 3.6--所以很多新的hibernate功能都不適用。 – 2012-07-30 22:06:51

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