Thursday, May 15, 2014

Spring Tutorial : Develop your Software based on Spring 4, JPA 2.0 and JBoss EAP 6.2 / JBoss AS 7.3

Removed
I will speak today about how can we integrate Spring 4 with JBoss AS 7 (JBoss EAP 6). 

Step 1 : Persistence.xml

The persistence.xml creation will depend on weather the Entity Manager will be managed by the container (JBoss so JPA 2.0) or by Spring (Where we will use JPA 2.1).

JBoss manage the EntityManager: Use of JPA 2.0 with JTA transaction Type

In this case, the Transaction Type must be JTA. JBoss EAP 6.2 (based on JBoss 7.3) comes with JPA2.0 :


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" 
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="module_enterprise" transaction-type="JTA">
  <jta-data-source>java:/myDS</jta-data-source>   
   <properties> 
   <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
   <property name="hibernate.show_sql" value="true" />
   <property name="hibernate.hbm2ddl.auto" value="validate"/>
  </properties>
 </persistence-unit>  
</persistence>

- Spring manage the EntityManager: Use of JPA2.0 with RESOURCE_LACAL transaction type


As we need to let Spring manage the persisitence unit and e want to use RESOURCE_LOCAL transaction type, we need to exclude JPA and Hibernate coming from JBoss.
So the steps are:
- Create a jpa-persistence.xml. In the case where you don't want that JBoss inject its own libraries, it is better to change the name of the persistence.xml ( JBoss will load JPA implicitely if it detects perssistence.xml file).

- Use RESOURCE_LOCAL and not JTA, if you don't really need to access multiple data sources

- Use "org.hibernate.jpa.HibernatePersistenceProvider" as a provider

- Add a property in the persistence.xml
<property name="jboss.as.jpa.managed" value="false"/>

In fact, according to JBoss Reference, jboss.as.jpa.managed can be set to false to disable container managed JPA access to the persistence unit.  The default is true, which enables container managed JPA access to the persistence unit.  This is typically set to false for Seam 2.x + Spring applications. 


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<!-- <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="module_enterprise" transaction-type="RESOURCE_LOCAL">
  <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
  <non-jta-data-source>java:/myDataSource</non-jta-data-source>   
   <properties> 
   <property name="jboss.as.jpa.managed" value="false" />
   <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
   <property name="hibernate.show_sql" value="true" />
   <property name="hibernate.hbm2ddl.auto" value="validate"/>
  </properties>
 </persistence-unit>  
</persistence>

Step 2 : Spring Configuration

Same think here: 

JBoss manage the EntityManager or EntityManagerFactory and Spring have just the jndi nameTransaction Type here must be JTA. The ApplicationContext looks like this:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jee="http://www.springframework.org/schema/jee"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
 http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

 <!-- post-processors for all standard config annotations -->
 <tx:annotation-driven />
 <context:annotation-config />
 <context:component-scan base-package="org.test"/>
 
 <jee:jndi-lookup id="myDataSource" jndi-name="java:/myDS"/>
 <jee:jndi-lookup id="entityManagerFactory_module" jndi-name="java:comp/env/test/myfact"  expected-type="javax.persistence.EntityManagerFactory"/>   
 <tx:jta-transaction-manager/>
</beans> 


In this case, the application uses a server-deployed persistence unit. Thus the javax.persistence classes and the persistence provider (Hibernate) are contained in modules in JBoss ( in JBOSS_HOME\modules\system\layers\base\javax\persistence\api\main) and added automatically by the application while the deployment (When detecting the persistence.xml or persistence-unit, JBoss inject implicitly Hibernate).
So using the server-deployed persistence unit, you need also to declare the JNDI persistence context in the Web.xml:
NB: The persistence-unit-name specified in web.xml should be the same  in perssitence.xml file  ( <persistence-unit name="module_enterprise" )


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" metadata-complete="true">

 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <persistence-unit-ref>
  <persistence-unit-ref-name>test/myfact</persistence-unit-ref-name>
  <persistence-unit-name>module_enterprise</persistence-unit-name>
 </persistence-unit-ref>
</web-app>

Note here that the name that we have declared in the application context is java:comp/env/test/myfactand in the web.xml, we need to put just test/myfact

If Spring cannot find the Default JBoss transaction Manager, you can guide it like explained in this post.

- Spring manage the EntityManager.

Using JPA2.0, we can enable the JPA in JBoss and use the first possibility. But as we have disabled JPA in JBoss, Spring is now responsible of creating th Transaction and the EntityManagerFactory.
My applicationContext looks like this:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jee="http://www.springframework.org/schema/jee"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
 http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

 <!-- post-processors for all standard config annotations -->
 <tx:annotation-driven />
 <context:annotation-config />
 <context:component-scan base-package="org.test"/>
 
 <jee:jndi-lookup id="myDataSource" jndi-name="java:/myDataSource"/>
 
 <bean id="emfEnterprise" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="dataSource" ref="myDataSource" />
  <property name="jpaVendorAdapter" ref="jpaAdapter" />
  <property name="persistenceUnitName" value="module_enterprise"/>
   <property name="persistenceXmlLocation" value="classpath*:META-INF/jpa-persistence.xml"/>  
 </bean> 
 
 <bean id="mddEnterpriseTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
  <property name="entityManagerFactory" ref="emfEnterprise" />
 </bean> 

  <bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="showSql" value="true" />
        <property name="generateDdl" value="true" />
        <property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect" />
    </bean>
</beans>



That's all, so now you are able to integrate JBoss with Spring either by allowing JBoss manage your persistence unit or by letting only Spring doing this and EXCLUDE JBOSS JPA and Hibernate modules.




2 comments :

  1. thanks for the tutorial; will it be also possible to share some sample code? really appreciate your helping mind :)

    ReplyDelete

Articles les plus consultés