开发者

Sharing a persistence unit across components in a .ear file

开发者 https://www.devze.com 2023-01-22 19:14 出处:网络
In a Java EE 6 application where I\'m using .ear packaging, I\'d like to create a persistence unit that can be accessed fr开发者_如何学编程om components in different .jar files.

In a Java EE 6 application where I'm using .ear packaging, I'd like to create a persistence unit that can be accessed fr开发者_如何学编程om components in different .jar files.

However, I'm not sure how to define this persistence unit. With the @PersistenceContext annotation the lookup only succeeds if the name matches a persistence unit defined in the local persistence.xml file.

Is it possible to refer to external persistence units?


Here are the relevant sections of the JPA 2.0 specification:

8.2 Persistence Unit Packaging

...

A persistence unit is defined by a persistence.xml file. The jar file or directory whose META-INF directory contains the persistence.xml file is termed the root of the persistence unit. In Java EE environments, the root of a persistence unit must be one of the following:

  • an EJB-JAR file
  • the WEB-INF/classes directory of a WAR file[80]
  • a jar file in the WEB-INF/lib directory of a WAR file
  • a jar file in the EAR library directory
  • an application client jar file

It is not required that an EJB-JAR or WAR file containing a persistence unit be packaged in an EAR unless the persistence unit contains persistence classes in addition to those contained within the EJB-JAR or WAR. See Section 8.2.1.6.

NOTE: Java Persistence 1.0 supported use of a jar file in the root of the EAR as the root of a persistence unit. This use is no longer supported. Portable applications should use the EAR library directory for this case instead. See [9].

A persistence unit must have a name. Only one persistence unit of any given name must be defined within a single EJB-JAR file, within a single WAR file, within a single application client jar, or within an EAR. See Section 8.2.2, “Persistence Unit Scope”.

The persistence.xml file may be used to designate more than one persistence unit within the same scope.

All persistence classes defined at the level of the Java EE EAR must be accessible to all other Java EE components in the application - i.e. loaded by the application classloader - such that if the same entity class is referenced by two different Java EE components (which may be using different persistence units), the referenced class is the same identical class.

And later:

8.2.2 Persistence Unit Scope

An EJB-JAR, WAR, application client jar, or EAR can define a persistence unit.

When referencing a persistence unit using the unitName annotation element or persistence-unit-name deployment descriptor element, the visibility scope of the persistence unit is determined by its point of definition:

  • A persistence unit that is defined at the level of an EJB-JAR, WAR, or application client jar is scoped to that EJB-JAR, WAR, or application jar respectively and is visible to the components defined in that jar or war.
  • A persistence unit that is defined at the level of the EAR is generally visible to all components in the application. However, if a persistence unit of the same name is defined by an EJB-JAR, WAR, or application jar file within the EAR, the persistence unit of that name defined at EAR level will not be visible to the components defined by that EJB-JAR, WAR, or application jar file unless the persistence unit reference uses the persistence unit name # syntax to specify a path name to disambiguate the reference. When the # syntax is used, the path name is relative to the referencing application component jar file. For example, the syntax ../lib/persistenceUnitRoot.jar#myPersistenceUnit refers to a persistence unit whose name, as specified in the name element of the persistence.xml file, is myPersistenceUnit and for which the relative path name of the root of the persistence unit is ../lib/persistenceUnitRoot.jar. The # syntax may be used with both the unitName annotation element or persistence-unit-name deployment descriptor element to reference a persistence unit defined at EAR level.

Also you need to include entity classes jar in manifest of pu jar http://wiki.eclipse.org/Packaging_and_Deploying_EclipseLink_JPA_Applications_(ELUG)

To summarize, you should be able to define your entities and the persistence unit at the top level of the EAR and to use them from the other modules.

I'm just not sure to understand what you tried and what problem(s) you faced.


The problem could be solved by placing a persistence.xml in a jar file that is located in the ear's lib directory.

The persistence.xml must contain the jar files which includes the Entities. I had to give the relative path to the jar files. My ear irectory structure

|-ear--
       |-lib--|... some libs ...
       |      |--my-persistence-xml.jar
       |-ejb-with-entities1.jar
       |-ejb-with-entities2.jar

My persistence.xml for jboss 7.1.1

<persistence-unit name="my-pu" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:jboss/datasources/mypu</jta-data-source>
    <jar-file>../ejb-with-entities1.jar</jar-file>
    <jar-file>../ejb-with-entities1.jar</jar-file>
    <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
        <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
        <property name="hibernate.show_sql" value="true"/>
        <property name="hibernate.format_sql" value="true" />
    </properties>
 </persistence-unit>

Hope this helps


All you need

EAR +
    |- META-INF +
    |       - persistence.xml
    |- ejb1-module.jar
    |- ejb2-module.jar


<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
    <persistence-unit name="my-persistence-unit">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>MyDataSource</jta-data-source>
        <!-- Note: it's relative to `persistence-module.jar` file location in EAR -->
        <jar-file>../ejb1-module.jar</jar-file>
        <jar-file>../ejb2-module.jar</jar-file>
        <properties>
            ...

        </properties>
    </persistence-unit>
</persistence>


Example working EAR layout for Glassfish:

EAR +
    |- lib +
    |      |- core-module.jar
    |      \- persistence-module.jar +
    |                                 \- META-INF +
    |                                              \- persistence.xml
    |- ejb1-module.jar
    \- ejb2-module.jar

EJB modules may be either jar archives or exploded directories.

In this case your persistence.xml may be like:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
    <persistence-unit name="my-persistence-unit">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>MyDataSource</jta-data-source>
        <!-- Note: it's relative to `persistence-module.jar` file location in EAR -->
        <jar-file>../ejb1-module.jar</jar-file>
        <jar-file>../ejb2-module.jar</jar-file>
        <properties>
            <property name="hibernate.current_session_context_class" value="jta"/>
            <property name="hibernate.id.new_generator_mappings" value="true"/>
            <property name="hibernate.dialect"      value="org.hibernate.dialect.PostgreSQL82Dialect"/>
            <property name="hibernate.show_sql"     value="true"/>
            <property name="hibernate.format_sql"   value="true"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
        </properties>
    </persistence-unit>
</persistence>

You have to update <jar-file> references if you use module versioning (e.g. ejb1-module-1.0-SNAPSHOT.jar).

Abstract objects with @MappedSuperclass annotation and EntityManager injection may be placed in any external jar. This jar does not require to be mentioned in persistence.xml. For example, you can create core-module.jar with PersistableEntity.java:

public class PersistableEntity {
    @Id
    @GeneratedValue
    private Long id;

    public Long getId() { return id; }

    public Integer getVersion() { return version; }
}

And PersistableEntityManager.java:

public class PersistableEntityManager<T extends PersistableEntity> {
    @PersistenceContext
    protected EntityManager em;
}

This core-module.jar could be used by all your projects with different persistence units. You just inherit your Entities and EJBs and avoid boilerplate. Check out example bilionix-core on github.


Try with this:

  1. Configure EAR application.xml file in this way:

    http://xmlns.jcp.org/xml/ns/javaee/application_7.xsd" version="7"> YourEEApplication

    <initialize-in-order>true</initialize-in-order> <!-- This is the most important thing -->
    
    <module>
        <ejb>YourEJBModule1.jar</ejb>
    </module>
    <module>
        <ejb>YourEJBModule2.jar</ejb>
    </module>
    ......
    <module>
        <ejb>YourEJBModuleX.jar</ejb>
    </module>
    
    <module>
        <web>
            <web-uri>YourWebModule.war</web-uri>
            <context-root>YourWebModule</context-root>
        </web>
    </module>
    

  2. In your EJB projects YourEJBModule1, YourEJBModule2... and YourEJBModuleX:

Inject Persistence Context whitout the unitName property:

@PersistenceContext(type=PersistenceContextType.TRANSACTION)
    private EntityManager em; // get & set
  1. For each EJB module persistence.xml file:

YourEJBModule1:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
    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">
    <persistence-unit name="PersistenceUnit1"
        transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>

        <jta-data-source>jdbc/YourDataSource</jta-data-source>
        <class>com.example.Foo1</class>
        <!-- Other properties -->
    </persistence-unit>
</persistence>

YourEJBModule2:

<?xml version="1.0" encoding="UTF-8"?>
...
    <persistence-unit name="PersistenceUnit2"
        transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>

        <jta-data-source>jdbc/YourDataSource</jta-data-source>
        <jar-file>YourEJBModule1.jar</jar-file>
        <class>com.example.Foo2</class>
        <!-- Other properties -->
    </persistence-unit>
...

YourEJBModuleX:

<?xml version="1.0" encoding="UTF-8"?>
...
    <persistence-unit name="PersistenceUnitX"
        transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>

        <jta-data-source>jdbc/YourDataSource</jta-data-source>
        <jar-file>YourEJBModule1.jar</jar-file>
        <jar-file>YourEJBModule2.jar</jar-file>
        ......
        <class>com.example.FooX</class>
        <!-- Other properties -->
    </persistence-unit>
...

In the database can exists various schemas, one per EJB module, access them through jta-data-source

(Deployed in Glassfish 4)


Here's what I did.

1) Package the persistence configuration files in a jar file. The jar file will contain:

  • META-INF/persistence.xml (and orm.xml if you use one)
  • Create a "lib" folder under the EAR project and stick the jar in there

2) Package the associated entity classes in another jar:

  • Put this jar file in your GlassFish domain/lib folder (or whatever lib folder equiv in other servers)
  • I initially bundled the jar in the EAR's "lib" folder but classes were not found
  • If anyone knows a better way to handle this please explain

The Persistence Context should now be accessible to all EJB and Web Apps bundled in your Enterprise Application.


I wanted to achieve shared persistance EJB module without EAR project.

This is possible by

  1. moving all persistance entities to separate EJB project (do not move persistance.xml to new project, only classes are needed
  2. compiling this EJB project
  3. sending project to GlassFish server using
scpAsSudo ~/NetbeansProjects/UnifyEntities/dist/UnifyEntities.jar remoteUsername@192.168.0.1:/opt/glassfish3/domains/domain1/lib/ext

Have fun!

0

精彩评论

暂无评论...
验证码 换一张
取 消