This is the third part in a series of blog posts highlighting some of the new features available in Spring Integration 2.2 following the recent release of Release Candidate 1. The first part described the new set of MongoDB adapters. In part two we highlighted the new extended support for synchronizing non-transactional resources with transactions.
In this third part today, we would like to introduce the new Java Persistence API (JPA) support that is provided starting with Spring Integration 2.2. The JPA module is persistence-provider-agnostic and has been tested using:
As part of the new JPA module, we provide several components for retrieving and persisting JPA entity objects:
- JPA Inbound Channel Adapter
- JPA Outbound Channel Adapter
- JPA Updating Outbound Gateway
- JPA Retrieving Outbound Gateway
Using these components, you can select, create, update and delete entities in your database. Besides persisting data using the entity classes directly, you can also execute queries using the Java Persistence Query Language (JPQL) as well as using native SQL queries. Additionally, named queries are supported as well.
The JPA Sample
In our Spring Integration Samples repository, we provide a sample application demonstrating the JPA support, which we want to use in this blog post to show you how to easily get started.
The provided sample is using an embedded H2 database which contains a single table called PEOPLE. This table is mapped to the Person entity class in package org.springframework.integration.samples.jpa. With that setup we cover two simple use-cases:
- List all people from the database
- Create a new Person record in the database
The corresponding Spring Integration flow is quite simple as well. The flow is started via a Messaging Gateway. This allows us to hide the Spring Integration messaging API and to only expose a plain Java interface (PersonService) to the sample’s Main class (org.springframework.integration.samples.jpa.Main). Depending on which method is invoked on the PersonService, the Spring Integration message will be routed to either a JPA Retrieving Outbound Gateway (List all people) or a JPA Updating Outbound Gateway (Create a new Person).
Execute the Sample
$ git clone https://github.com/SpringSource/spring-integration-samples.git
Next, go to the JPA sample directory:
$ cd spring-integration-samples/basic/jpa
Now we can build and run the application by executing the following Maven command:
$ mvn clean package exec:exec
Eventually the application starts up and you should see the following screen:
========================================================= Welcome to the Spring Integration JPA Sample! For more information please visit: http://www.springintegration.org/ ========================================================= Please enter a choice and press enter: 1. Use Hibernate 2. Use OpenJPA 3. Use EclipseLink q. Quit the application Enter you choice:
The JPA sample allows you to execute the JPA operations using one of the following persistance providers: Hibernate, OpenJPA or EclipseLink. At application startup you will therefore be able to choose the desired persistence provider. Once selected, you can select which specific JPA operation to execute:
Please enter a choice and press enter: 1. List all people 2. Create a new person q. Quit the application Enter you choice:
You can either list each Person from the PEOPLE table (Option 1):
Enter you choice: 1 ID NAME CREATED ================================== 1001, Cartman, 2012-10-04 16:14:02 ==================================
or you can create a new Person (Option 2):
Enter the Person's name:Demo User Created person record with id: 1002 Do you want to create another person? (y/n) ...
The JPA sample is configured using several Spring XML Application Context files. For the most part, Spring Integration’s JPA support uses the JPA support provided by the core Spring Framework. Thus, the common JPA configuration is located at:
This file does not contain anything Spring Integration specific. All we do, is to setup the embedded database, the respective DataSource, the EntityManagerFactory and the Transaction Manager.
The JPA persistence provider specific configuration is located under:
/src/main/resources/META-INF/spring/integration/eclipselink-context.xml /src/main/resources/META-INF/spring/integration/hibernate-context.xml /src/main/resources/META-INF/spring/integration/openjpa-context.xml
As you will see, these configurations are very light-weight, containing only the persistence provider specific JpaVendorAdapter bean declarations.
Everything Spring Integration specific is configured in:
<?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:int="http://www.springframework.org/schema/integration" xmlns:int-jpa="http://www.springframework.org/schema/integration/jpa" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd 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/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/integration/jpa http://www.springframework.org/schema/integration/jpa/spring-integration-jpa.xsd"> <int:channel id="createPersonRequestChannel"/> <int:channel id="listPeopleRequestChannel"/> <int:gateway id="personService" service-interface="org.springframework.integration.samples.jpa.service.PersonService" default-request-timeout="5000" default-reply-timeout="5000"> <int:method name="createPerson" request-channel="createPersonRequestChannel"/> <int:method name="findPeople" request-channel="listPeopleRequestChannel"/> </int:gateway> <int-jpa:retrieving-outbound-gateway entity-manager-factory="entityManagerFactory" request-channel="listPeopleRequestChannel" jpa-query="select p from Person p order by p.name asc"> </int-jpa:retrieving-outbound-gateway> <int-jpa:updating-outbound-gateway entity-manager-factory="entityManagerFactory" request-channel="createPersonRequestChannel" > <int-jpa:transactional transaction-manager="transactionManager" /> </int-jpa:updating-outbound-gateway> <!-- Depending on the selected profile, users can use different JPA Providers --> <beans profile="default, hibernate"> <import resource="classpath:/META-INF/spring/integration/hibernate-context.xml"/> </beans> <beans profile="openjpa"> <import resource="classpath:/META-INF/spring/integration/openjpa-context.xml"/> </beans> <beans profile="eclipselink"> <import resource="classpath:/META-INF/spring/integration/eclipselink-context.xml"/> </beans> </beans>
Both, the Retrieving Outbound Gateway and the Updating Outbound Gateway are wired up with an EntityManagerFactory reference. Alternatively, we also provide means to pass-in a reference to an EntityManager directly.
The Retrieving Outbound Gateway is also configured with an JPQL query to retrieve all people from the database ordered by their name. The Updating Outbound Gateway on the other hand does not specify any queries at all. It directly uses the Person object that is being passed in as the Spring Integration Message payload. Ultimately, the Person object is passed to the EntityManager and persisted to the database. Furthermore, the Updating Outbound Gateway is being declared transactional ensuring that the JPA session is flushed and the data committed to the database.
Not shown in the example above but with the JPA supporting components you are also able to provide parameters for your JPQL/SQL queries. In order to do so, you can use the
sub-element. For example, you can provide Named Parameters by specifying:
<int-jpa:parameter name="myNamedParam" type="java.lang.String" value="myParamValue"/>
Alternatively, you can also provide Positional Parameters by leaving off the name attribute:
<int-jpa:parameter type="java.lang.String" value="myFirstParam"/> <int-jpa:parameter type="java.lang.Integer" value="2"/>
Lastly, if you are using the Outbound Channel Adapter or any of the Outbound Gateways, you can also provide dynamic parameters using the Spring Expression Language (SpEL), giving you easy access to values from the Message’s payload or its Message headers:
<int-jpa:parameter expression="payload.name" name="firstName"/>
We hope that this blog post provides you with an useful overview of the new Spring Integration JPA support. For much more detailed information, please consult the chapter titled JPA Support in the Spring Integration reference manual. Lastly, if you run into any trouble or have additional questions, please feel free to post those to our Spring Integration Forum.