SpringDM笔记21-Using ORM within OSGi with Spring DM

Version

1.Object/relational mapping

   (1)JPA CONCEPTS

   Although any database-based Java application must rely on JDBC, there’s a structural mismatch

betweenobject-orientedapplications,whicharebasedonobjects,andrelationaldatabases,

   which are based on rows, tables, and relations.This structural mismatch causes some issues that

   are difficult to resolve when directly using JDBC:

   ■ Handling specific SQL dialects

   ■ N+1 selects

   ■ Object graph handling

   ■ Object mapping

   ORM allows you to manage entities through corresponding tables in the database: that’s the

   structural part of ORM. It also has a conversational part, in which the lifecycle of entities is

   introduced through several states. Transitions between these states allow the JPA engine to

   detect the operations that trigger the persistence context to be flushed or synchronized.

   The persistence context contains all the persistence instances currently manipulated by JPA. This  

   context can be thought of as a first-level cache for the calling code. In enterprise applications, this 

   context is commonly associated with a transaction or a web request and is flushed at the end of

   each.

   JPA methods controlling transitions in the mapped object lifecycle:

   ■ getReference and find:Allow you to get persistent entities from the database. Updates to these      entities are automatically synchronized with the database on a flush operation. Related SQL 

      equests correspond to SELECT requests.

   ■ persist:Allows you to create persistent entities in order to add them to the database. Related SQL

      requests correspond to INSERT requests.

   ■ merge:Allows you to attach detached entities. This operation results in persistent entities.

      Related SQL requests correspond to UPDATE requests.

   ■ delete:Allows you to remove persistent entities from the database. Related SQL requests

      correspond to DELETE requests.

   ■ flush and commit:Allow you to execute SQL requests corresponding to operations done on the

      persistent context. All pending transitions on managed entities, except for loading, are done at

      this point.

   (2)JAVA PERSISTENCE API

    JPA实现:Hibernate JPA,OpenJPA,EclipseLink。

    Implementation of the Contact class using JPA annotations for mapping:

    @Entity

publicclassContact{

@Id

@Column(name="id")

@GeneratedValue(strategy=GenerationType.AUTO)

privateintid;

@Column(name="last_name")

privateStringlastName;

@Column(name="first_name")

privateStringfirstName;

@OneToMany(mappedBy="contact",fetch=FetchType.EAGER,cascade=CascadeType.ALL)

privateList<Address>addresses;

(...)

    }

    persistence.xml file: (It’s commonly located under the METAINF directory)

    <persistence xmlns="http://java.sun.com/xml/ns/persistence"  version="1.0">

     <persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL">

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

<class>com.manning.sdmia.dataaccess.domain.model.Contact</class>

<class>com.manning.sdmia.dataaccess.domain.model.Address</class>

</persistence-unit>

   </persistence>

   The main abstractions of this API are the EntityManager and EntityManagerFactory interfaces:

   ■ The EntityManager is associated with a persistence context and provides a set of methods to

      interact with it. This interface is responsible for loading data and updating the states of managed

      entities.   ■ The EntityManagerFactory interface corresponds to the EntityManager’s factory and is in charge

      of loading the persistence.xml file as part of its creation.

   Using the EntityManager interface:

   EntityManagerFactory emf = getEntityManagerFactory();

EntityManagerem=null;

try{

em=emf.createEntityManager();

entityManager.getTransaction().begin();

Contactcontact=newContact();

contact.setLastName("Piper");

contact.setFirstName("Andy");

em.persist(contact);

entityManager.getTransaction().commit();

}catch(Exceptionex){

(...)

entityManager.getTransaction().rollback();

}finally{

closeEntityManager(em);

   }

   Using the EntityManager interface:

   EntityManagerFactory emf = getEntityManagerFactory();

EntityManagerem=null;

Try{

em=emf.createEntityManager();

Queryquery=em.createQuery("selectcfromContact");

List<Contact>contacts=query.getResultList();

for(Contactcontact:contacts){

(...)

}

}catch(Exceptionex){

(...)

}finally{

          closeEntityManager(em);

   }

2.Load-time weaving(LTW)

   Some JPA implementations have made the choice to use load-time weaving (LTW) to instrument

   managed entities. Because LTW is tied to classloading, and LTW isn’t supported by all OSGi

   containers.

   (1)LOAD-TIME WEAVING CONCEPTS

   Load-time weaving (LTW) is related to AOP. Without going into details, the term “weaving” refers

   to the way aspects are applied to the application code. The weaving mechanism isn’t

   standardized and several approaches exist:

■Compilation-timeweaving—Javacodeisupdatedtoaddaspectsbeforeitscompilation

■Binaryweaving—Updatesbytecodetoaddaspectsafteritscompilation

   ■ Load-time weaving—Modifies the bytecode of classes as they’re loaded into a JVM

   LTW updates class content as classes are loaded. Several mechanisms in Java can be used to

   implement it:

   ■ Dedicated classloader—A dedicated classloader is used to update classes as they’re loaded.   ■ Java 5 agent—Java 5 introduced the concept of a Java agent, which makes it possible to

      instrument classes while loading them. This mechanism is based on the Instrumentation and

      ClassFileTransformer interfaces. The latter specifies how to transform classes and must be

      registered through the Instrumentation interface.   ■ Java 6 class redefinition—Java 6 allows you to redefine classes to update their logic after JVM

      startup. In this case, the ClassDefinition interface can be defined and registered through the

      Instrumentation interface.   ■ Class enhancer tools—Such tools work by putting a proxy in front of instances to add logic

      around method execution. Usually these tools create subclasses dynamically. This approach

      isn’t transparent to the application because it must use the tools’ API to obtain updated

      instances.

   (2)Using LTW with the Equinox container and Spring

   EQUINOX ASPECTS:

   The Equinox Aspects tool is dedicated to leveraging AOP across all present OSGi components within

   an Equinox instance, and it enables LTW using the container’s hooks.

   Equinox Aspects takes advantage of the extensible nature of the Equinox Framework:the Equinox

   Framework adaptor hooks are responsible for handling internal mechanisms like classloading. This

   feature allows you to hook into the framework through the hookable adaptor, which allows you to

   add extensions to insert additional functionality into the framework itself. For example,

   ClassLoadingHook makes possible various classloader extensions, most specifically bytecode

   weaving.

      These extensions must be defined as fragments for the system bundle org.eclipse.osgi. To enable

   their loading, the container must be launched using the osgi.framework.extensions system property.

   These fragments aren’t considered regular bundles because they must be discovered before the

   platform is launched.

   Required components for using Equinox Aspects:

   ■ org.eclipse.equinox.weaving.hook:Equinox hook implementation

   ■ org.eclipse.equinox.weaving.aspectj:Bridge between Equinox Aspects and AspectJ

   ■ org.eclipse.equinox.weaving.caching:Optional component for caching

   ■ org.eclipse.equinox.weaving.caching.j9:Optional component for caching

   ■ com.springsource.org.aspectj.runtime:AspectJ runtime component

   ■ com.springsource.org.aspectj.weaver:AspectJ weaver component

   (3)EQUINOX ASPECTS ADAPTER FOR SPRING

   An open LTW implementation for Equinox Aspects:

   http://forum.springsource.org/showthread.php?t=60253&page=2

   Once the org.eclipse.equinox.weaving.springweaver package is imported in the manifest

   configuration, along with the other packages required by Equinox Aspects, the implementation can

   be configured in a Spring container as shown in the following snippet:

   <bean class="org.eclipse.equinox.weaving.springweaver.EquinoxAspectsLoadTimeWeaver"/>

   或者配置成:

   <context:load-time-weaver weaver-class="org.eclipse.equinox.weaving.springweaver 

              .EquinoxAspectsLoadTimeWeaver"/>

3.Provisioning a container for JPA implementations

   (1)COMMON SPRING JPA COMPONENTS

   PROVISIONING FOR HIBERNATE JPA:

   ■ Group ID: javax.persistence

   Artifact ID:com.springsource.javax.persistence

   Version:1.0.0

   ■ Group ID:org.springframework

   Artifact ID:org.springframework.transaction

   Version:3.0.0.M1

   ■ Group ID:org.springframework

   Artifact ID:org.springframework.jdbc

   Version:3.0.0.M1

   ■ Group ID:org.springframework

   Artifact ID:org.springframework.orm

   Version:3.0.0.M1

   (2)PROVISIONING FOR HIBERNATE JPA

   Hibernate JPA bundles and their dependencies from the SpringSource EBR:

   com.springsource.org.hibernate.ejb :3.4.0.GA

   com.springsource.org.hibernate.annotations.common :3.3.0.ga

   com.springsource.org.hibernate.annotations :3.4.0.GA

   com.springsource.org.hibernate :3.3.1.GA

   com.springsource.org.apache.commons.beanutils :1.7.0

   com.springsource.org.apache.commons.codec :1.3.0

   com.springsource.org.apache.commons.collections: 3.2.0

   com.springsource.org.apache.commons.digester:1.8.0

   com.springsource.org.apache.commons.io :1.4.0

   com.springsource.org.apache.commons.lang :2.4.0

   com.springsource.org.apache.commons.pool :1.4.0

   com.springsource.antlr :2.7.7

   com.springsource.javassist :3.3.0.ga

   com.springsource.javax.xml.stream :1.0.1

   com.springsource.org.dom4j :1.6.1

   com.springsource.org.jgroups :2.5.1

   com.springsource.org.objectweb.asm :1.5.3

   com.springsource.org.objectweb.asm.attrs :1.5.3

   com.springsource.javax.transaction :1.1.0

   (3)PROVISIONING FOR OPENJPA

   OpenJPA bundles and their dependencies from the SpringSource EBR  

   com.springsource.org.apache.openjpa:1.1.0

   com.springsource.org.apache.commons.lang:2.4.0

   com.springsource.org.apache.commons.collections:3.2.1

   com.springsource.org.apache.commons.pool:1.4.0

   com.springsource.org.objectweb.asm:2.2.3

   com.springsource.serp:1.13.1

   com.springsource.javax.transaction:1.1.0

   (4)PROVISIONING FOR ECLIPSELINK

   EclipseLink bundles and their dependencies from the SpringSource EBR:

   com.springsource.org.eclipse.persistence:1.0.0

   com.springsource.org.eclipse.persistence.jpa:1.0.0

   com.springsource.org.eclipse.persistence.asm:1.0.0

   com.springsource.org.eclipse.persistence.antlr:1.0.0

3.Using JPA in OSGi with Spring DM

   (1)CONFIGURING JPA WITH SPRING SUPPORT

   Spring’s JPA support provides two classes to configure JPA and its underlying implementation:   LocalEntityManagerFactoryBean and LocalContainerEntityManagerFactoryBean. These classes

   implement Spring’s FactoryBean interface and allow you to configure a JPA factory of type

   EntityManagerFactory.

   The LocalEntityManagerFactoryBean class is the simplest way to configure JPA in Spring. It uses

   an autodetection mechanism to discover the configured JPA implementation from the persistence.xml

   file located in the META-INF directory in the classpath,but it provides no way to link to an existing

   JDBC data source configured in Spring.This makes it impossible to use this abstraction in an OSGi

   environment, because data sources are registered as OSGi services.

   The LocalContainerEntityManagerFactoryBean class is more flexible and particularly suitable when

   using JPA with OSGi. It allows you to inject a data source and specify a chosen JPA implementation.

   The LocalContainerEntityManagerFactoryBean class is based on implementations of the

   JpaVendorAdapter interface. Implementations of this interface can be injected in this class to select

   the JPA implementation to use. Built-in implementations of this interface are listed follow:. All these 

   implementations are located in the org.springframework.orm.jpa.vendor package:

   Hibernate JPA:org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter

   OpenJPA:org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter

   EclipseLink:org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter

  

   Configuration of the Hibernate JPA implementation with Spring:

   <bean id="entityManagerFactory"   

         class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

<propertyname="dataSource"ref="dataSource"/>

<propertyname="jpaVendorAdapter"ref="hibernateJpaVendorAdapter"/>

         <property name="persistenceXmlLocation"

         value="classpath:/com/manning/spring/osgi/jpa/domain/dao/impl/persistence.xml"/>   </bean>

   <bean id="hibernateJpaVendorAdapter"

class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">

<propertyname="databasePlatform"value="org.hibernate.dialect.HSQLDialect"/>

<propertyname="showSql"value="true"/>

    </bean>

    注意:The persistenceXmlLocation property is optional. If this property isn’t specified, the 

    LocalContainerEntityManagerFactoryBean class uses the persistence.xml file under the META-INF

    directory.

    下面的Package需要Import:

    Import-Package: (...)

javax.persistence;version="1.0.0",

org.springframework.beans.factory;version="3.0.0.M1",

org.springframework.core;version="3.0.0.M1",

org.springframework.dao.support;version="3.0.0.M1",

org.springframework.orm.jpa;version="3.0.0.M1",

org.springframework.orm.jpa.support;version="3.0.0.M1",

    org.springframework.orm.jpa.vendor;version="3.0.0.M1"

    (2)USING JPA WITH JPATEMPLATE AND SPRING DM

    Spring’s JPA support provides the JpaDaoSupport class as a base class for all DAOs using the JPA

    technology. Having specified this class as a superclass for your DAO, you can inject an instance of

    EntityManagerFactory into your DAO and access a correctly configured instance of the template

    with the getJpaTemplate method.

    DAO structure using Spring’s JPA support:

    public class ContactsDaoImpl extends JpaDaoSupport implements ContactsDao {

publicContactgetContact(longid){

              return (Contact)getJpaTemplate().getReference(id, Contact.class);

        }

(...)

    }

    <bean id="entityManagerFactory" (...)>

(...)

</bean>

<beanid="contactsDao"

class="com.manning.sdmia.directory.dao.impl.ContactsDaoImpl">

<propertyname="entityManagerFactory"ref="entityManagerFactory"/>

    </bean>

4. JPA implementation specifics when used with Spring DM

    These are the requirements when using JPA in an OSGi environment:

    ■ Visibility of mapped classes—When configuring JPA implementations at runtime,the mapped

       classes must be visible.

    ■ Automatic discovery of mapped classes—JPA implementations provide support to autodiscover

       mapped classes. This feature has implications when used within an OSGi environment.

    ■ LTW—JPA implementations require or have the option for load-time class instrumentation.

      This feature has a big impact on components and the OSGi container itself, especially when

      using LTW.

    ■ Specific OSGi imports—In addition to the common packages described above, packages must be

      specified according to the chosen JPA implementation.

    (1) GENERAL ISSUES WITH OSGI

    You’ll probably recognize by now that the first issue when using JPA in OSGi is a class visibility

    one:mapped classes must be visible to the JPA implementation when creating the 

    EntityManagerFactory entity. Spring DM is smart enough to make these classes visible to

    components of the JPA implementation. Thanks to Spring DM’s TCCL support, the mapped

    classes only have to be visible to the component creating the EntityManagerFactory    (that’s a DAO implementation bundle in most cases).

        Another class visibility issue occurs when using classes enhanced (decorated) by the JPA

    implementation. JPA implementations tend to transparently instrument classes, and these

    “unexpected” classes must also be visible to the implementation as per OSGi visibility rules.

    These classes will obviously depend on the chosen JPA implementation.

        Moreover, some JPA implementations try to autodetect classes through classpath scanning for

    the Entity annotation. In an OSGi environment, this feature can cause  exceptions, as shown in

    the following snippet:

    Caused by: java.io.FileNotFoundException: /home/[...] /                       com.manning.sdmia.service.jpa.openjpa/bin/ (Is a directory)

    This happens because inspecting JAR files in OSGi doesn’t work the same way it does in classic

    Java applications. As a matter of fact, this inspecting is based on URLs using the bundlesource

    protocol. Because this isn’t handled by all JPA implementations, the JPA implementation may

    not be able to browse the contents of a component.

        Best practice is to deactivate this feature and to explicitly define which classes must be used

    by the JPA implementation. This can be done in the persistence.xml file, as shown in the

    following snippet:

    <persistence xmlns=http://java.sun.com/xml/ns/persistence version="1.0">

<persistence-unitname="directoryUnit"transaction-type="RESOURCE_LOCAL">

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

<class>com.manning.sdmia.dataaccess.domain.model.Contact</class>

</persistence-unit>

    </persistence>

    Forgetting to set the exclude-unlisted-classes parameter to true can cause some JPA  

    implementations to crash (such as OpenJPA).

    A JPQL problem when using Hibernate JPA. Using a request like the one shown in the following

    snippet raises a strange ClassCastException:

    from com.manning.sdmia.service.jpa.model.Author a left join a.books

        The exception it raised was this: java.lang.ClassCastException: [Ljava.lang.Object; can't be cast

    to com.manning.sdmia.service.jpa.model.Author

    Adding a select clause solves the problem, as shown in following snippet:    select a from com.manning.sdmia.service.jpa.model.Author a left join a.books

    (2)USING SPRING LTW AND JPA

    The JPA specification defines the contract for class transformation through the ClassTransformer

    interface. This interface must be implemented by persistence providers that want to transform

    entities and managed classes at class load time or at class redefinition time. This feature isn’t

    mandatory, and implementations are free to use or ignore it.    The following JPA implementations behave differently regarding LTW:

    ■ Visibility of mapped classes—Use the built-in support provided by Spring DM for making

       mapped classes visible when configuring JPA entities at runtime.    ■ Automatic discovery of mapped classes—Deactivate the automatic discovery of mapped

       classes using the exclude-unlisted-classes tag in the persistence. xml configuration file. This  

       feature isn’t commonly supported within an OSGi environment.    ■ LTW—Configure LTW if needed by the JPA implementation or if you want to use it and your

       JPA implementation allows it. In the Equinox container, LTW requires the use of Equinox

       Aspects and its integration with Spring’s LTW support.    ■ Specific OSGi imports—Specify all the additional packages in the Import-Package header

       for the chosen JPA implementation. These packages correspond to hidden classes used at

       runtime by implementations.

    Spring enables you to integrate ClassTransformer entities into its generic LTW support when their

    use is required for a JPA implementation. To use this support, you need to configure the LTW

    implementation that you want to use. In our case, that’s Equinox Aspects. This configuration can

    either be done globally through the loadtime-weaver facility of Spring’s context XML namespace

    or directly on the EntityManagerFactory, as shown in the following snippet:

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa

           .LocalContainerEntityManagerFactoryBean">

(...)

<propertyname="loadTimeWeaver">

<beanclass="org.eclipse.equinox.weaving.springweaver

.EquinoxAspectsLoadTimeWeaver"/>

</property>

    </bean>

    Remember that you must specify the osgi.framework.extensions system property with the value

    org.eclipse.equinox.weaving.hook to enable Equinox Aspects for LTW. Tracing can be activated for

    this feature by setting the org.aspectj.osgi.verbose system property to true.

    (3)SPECIFIC CONFIGURATION FOR HIBERNATE JPA

    The Hibernate JPA implementation doesn’t use LTW to instrument managed entities. Instead,

    The Hibernate JPA implementation uses Javassist to manipulate Java bytecode on the fly.

    下面的Package需要Import:

    Import-Package: (...)

javassist.util.proxy;version="3.3.0.ga",

org.hibernate.proxy;version="3.3.1.GA",

org.hibernate.jdbc;version="3.3.1.GA",

    (...)

    如果使用JPQL,还需要导入:

    org.hibernate.hql.ast

    This package must be added to the manifest configuration of the bundle whose classloader

    corresponds to the context classloader. Because OSGi doesn’t explicitly set the context

    classloader, Spring DM’s context classloader support can be used to address this issue by

    setting it on the service that exports the DAO entity.

    (4)SPECIFIC CONFIGURATION FOR OPENJPA

    需要导入下面的Package:

    Import-Package: (...)

org.apache.openjpa.enhance;version="1.1.0",

    org.apache.openjpa.jdbc.kernel;version="1.1.0"

    org.apache.openjpa.util;version="1.1.0"

orm

相关推荐