2011-12-09 31 views
29

Mam ten wymóg, aby dodać klasy jednostek do jednostki utrwalania w środowisku wykonawczym, zamiast określać je wszystkie w pliku persistence.xml. Czy ktoś może mi pomóc z tym samym?Dodawanie klas jednostek dynamicznie w środowisku wykonawczym

Jestem świadomy, że Hibernate posiada własny mechanizm robi to samo za pomocą:

AnnotationConfiguration.addAnnotatedClass(Class), etc - Można także dodać hibernacji config (*.hbm.xml) Pliki programowo.

Wymaganie jest takie, że bez restartowania serwera aplikacji powinienem mieć możliwość dynamicznego dodawania klas jednostek/ich plików konfiguracyjnych (mapowania) do jednostki trwałości.

Ale rozwiązanie do programowego dodawania klas jednostek/plików konfiguracyjnych w czasie wykonywania do jednostki utrwalania nie powinno być specyficzne dla implementacji JPA.

Odpowiedz

30

JPA nie oferuje jeszcze tej funkcji. Oto trzy opcje można sprawdzić:

EDIT:

Jeśli dostawca JPA jest Hibernacja, ponieważ Hibernate 4.0, możliwe jest przekazywanie bezpośrednio podmiotów do tego dostawcy JPA bez deklarowania ich w pliku persistence.xml. Hibernacja będzie obsługiwać podmioty w locie.

EDIT:

Oto przykładowa konfiguracja z JPA 2.1 + hibernacji 4.3.7.Final bez deklarowania żadnych podmioty:

META-INF/wytrwałość.xml

<?xml version="1.0" encoding="UTF-8" ?> 
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence 
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd" 
    version="2.1"> 

    <persistence-unit name="my-persistence-unit" 
     transaction-type="RESOURCE_LOCAL"> 
     <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> 
     <properties> 
      <!-- Database Properties --> 
      <property name="javax.persistence.jdbc.url" 
       value="jdbc:postgresql://localhost:5432/my-database" /> 
      <property name="javax.persistence.jdbc.user" value="login" /> 
      <property name="javax.persistence.jdbc.password" value="password" /> 

      <!-- Hibernate Properties --> 
      <property name="hibernate.connection.driver_class" value="org.postgresql.Driver" /> 
      <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" /> 
      <property name="hibernate.default_schema" value="public" /> 
      <property name="hibernate.hbm2ddl.auto" value="update" /> 
      <property name="hibernate.show_sql" value="false" /> 
      <property name="hibernate.format_sql" value="true" /> 

      <!-- Connection Pool --> 
      <property name="hibernate.c3p0.min_size" value="5" /> 
      <property name="hibernate.c3p0.max_size" value="20" /> 
      <property name="hibernate.c3p0.timeout" value="500" /> 
      <property name="hibernate.c3p0.max_statements" value="50" /> 
      <property name="hibernate.c3p0.idle_test_period" value="2000" /> 
     </properties> 
    </persistence-unit> 

</persistence> 

Referencje

+2

Czy możesz podać mi informacje, jak skonfigurować Hibernate, aby akceptować jednostki bez ich deklarowania? Wygląda na to, że nie jest to zachowanie domyślne. – Rafal

+0

Przepraszam za zaniedbanie, po próbie na innym Tomku działało jak czar.Jest to domyślne zachowanie i myślę, że zostało spowodowane z powodu wtyczki gradle-tomcat>. < – lucasvc

4

Jestem późno do partii, ale myślę, że będzie to zaoszczędzić trochę ludziom trochę głowa. Zaimplementowałem skanowanie ze ścieżkami klas czystego JPA (bez potrzeby użycia sprężyny), które integruje się z np. guice-persist również w razie potrzeby.

Oto, co musisz zrobić.

pierwsze, zmienić persistence.xml i dodać własną implementację, jak:

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence 
     http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd" 
     version="2.1"> 

<persistence-unit name="my.persistence.unit" transaction-type="RESOURCE_LOCAL"> 

    <provider>my.custom.package.HibernateDynamicPersistenceProvider</provider> 

    <exclude-unlisted-classes>true</exclude-unlisted-classes> 

    <properties> 
     <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" /> 
     <property name="hibernate.max_fetch_depth" value="30" /> 
     <property name="hibernate.hbm2ddl.auto" value="update" /> 
     <property name="hibernate.show_sql" value="true" /> 
    </properties> 
</persistence-unit> 

W celu dla dostawców, aby uznać, trzeba będzie zrobić to wykrywalne. JPA odkrywa użyciu mechanizmu ładowania usługa, więc dodajemy:

/src/main/resources/META-INF/services/javax.persistence.spi.PersistenceProvider 

Plik ten ma dokładnie jedną linię:

my.custom.package.HibernateDynamicPersistenceProvider 

Wreszcie dodać własne dostawcy i oprzeć go na HibernateProvider (Opieram to na tym, ponieważ chcę użyć hibernacji):

public class HibernateDynamicPersistenceProvider extends HibernatePersistenceProvider implements PersistenceProvider { 

    private static final Logger log = Logger.getLogger(HibernateDynamicPersistenceProvider.class); 

    public static final String CUSTOM_CLASSES = "CUSTOM_CLASSES"; 

    @Override 
    protected EntityManagerFactoryBuilder getEntityManagerFactoryBuilder(
      PersistenceUnitDescriptor persistenceUnitDescriptor, Map integration, ClassLoader providedClassLoader) { 

     if(persistenceUnitDescriptor instanceof ParsedPersistenceXmlDescriptor) { 
      ParsedPersistenceXmlDescriptor tmp = (ParsedPersistenceXmlDescriptor) persistenceUnitDescriptor; 
      Object object = integration.get("CUSTOM_CLASSES"); 
     } 

     return super.getEntityManagerFactoryBuilder(persistenceUnitDescriptor, integration, providedClassLoader); 
    } 

    protected EntityManagerFactoryBuilder getEntityManagerFactoryBuilderOrNull(String persistenceUnitName, Map properties, ClassLoader providedClassLoader) { 
     log.debug(String.format("Attempting to obtain correct EntityManagerFactoryBuilder for persistenceUnitName : %s", persistenceUnitName)); 

     final Map integration = wrap(properties); 
     final List<ParsedPersistenceXmlDescriptor> units; 
     try { 
      units = PersistenceXmlParser.locatePersistenceUnits(integration); 
     } 
     catch (Exception e) { 
      log.debug("Unable to locate persistence units", e); 
      throw new PersistenceException("Unable to locate persistence units", e); 
     } 

     log.debug(String.format("Located and parsed %s persistence units; checking each", units.size())); 

     if (persistenceUnitName == null && units.size() > 1) { 
      // no persistence-unit name to look for was given and we found multiple persistence-units 
      throw new PersistenceException("No name provided and multiple persistence units found"); 
     } 

     for (ParsedPersistenceXmlDescriptor persistenceUnit : units) { 
      log.debug(String.format(
        "Checking persistence-unit [name=%s, explicit-provider=%s] against incoming persistence unit name [%s]", 
        persistenceUnit.getName(), 
        persistenceUnit.getProviderClassName(), 
        persistenceUnitName 
      )); 

      final boolean matches = persistenceUnitName == null || persistenceUnit.getName().equals(persistenceUnitName); 
      if (!matches) { 
       log.debug("Excluding from consideration due to name mis-match"); 
       continue; 
      } 

      // See if we (Hibernate) are the persistence provider 

      String extractRequestedProviderName = ProviderChecker.extractRequestedProviderName(persistenceUnit, integration); 

      if (! ProviderChecker.isProvider(persistenceUnit, properties) && !(this.getClass().getName().equals(extractRequestedProviderName))) { 
       log.debug("Excluding from consideration due to provider mis-match"); 
       continue; 
      } 

      return getEntityManagerFactoryBuilder(persistenceUnit, integration, providedClassLoader); 
     } 

     log.debug("Found no matching persistence units"); 
     return null; 
    } 
} 

musiałem zastąpić 2 sposoby, pierwszy:

protected EntityManagerFactoryBuilder getEntityManagerFactoryBuilder(
      PersistenceUnitDescriptor persistenceUnitDescriptor, Map integration, ClassLoader providedClassLoader) 

To jest metoda przechwytywania. Dodałem niestandardową właściwość "CUSTOM_CLASSES", która naprawdę powinna być nazwana "CUSTOM_PACKAGES", która wyświetli wszystkie pakiety, które muszą zostać przeskanowane. W tym momencie jestem trochę leniwy i pomijam skanowanie rzeczywistej ścieżki klasowej, ale możesz to zrobić samemu - to całkiem proste. Następnie możesz zadzwonić pod numer

tmp.addClasses("class1", "class2"); 

Gdzie klasy są tymi, które odkryłeś.

Druga metoda jesteśmy nadrzędnym jest:

protected EntityManagerFactoryBuilder getEntityManagerFactoryBuilderOrNull(String persistenceUnitName, Map properties, ClassLoader providedClassLoader) 

To dlatego, że jesteśmy dostawcą rozszerzenie jest ustalony, aby umożliwić tylko zajęcia hibernacji w celu utworzenia EMF. Ponieważ mamy niestandardową klasę przechwytującą konstrukcję, nasze nazwy nie sumują się. Dodałem więc:

String extractRequestedProviderName = ProviderChecker.extractRequestedProviderName(persistenceUnit, integration); 

if (! ProviderChecker.isProvider(persistenceUnit, properties) && !(this.getClass().getName().equals(extractRequestedProviderName))) { 
     log.debug("Excluding from consideration due to provider mis-match"); 
     continue; 
} 

To rozszerza normalny test hibernacji, aby mój operator niestandardowy był ważny.

Wola, skończymy, masz teraz włączoną funkcję hibernacji, skanowanie klasy z JPA.

+0

Niektóre pytania: Dlaczego zadeklarowałeś CUSTOM_CLASSES jako stały i nigdy go nie używasz? Z której wersji Hibernate korzystasz? – Stephan

+0

CUSTOM_CLASSES nigdy nie jest używany, ponieważ jest to tylko przykładowa konfiguracja. Nie używam go ostro. Używam guice, aby wprowadzić mojego dostawcę do rzeczywistych podmiotów, które chcę zamiast tego. Używam Hibernuj 5.1.0.Final Możesz użyć CUSTOM_CLASSES do np. przekazywać nazwy pakietów, a następnie implementować własną wersję wykrywania pakietów. – pandaadb

+0

Od wersji Hibernate 4.0 można przekazywać do niej jednostki bez ich deklarowania. Czy ta funkcja zniknęła w wersji 5.1.0.Final? – Stephan

Powiązane problemy