Spring Integration JPA provides XML namespace support for declaring JPA components in Spring XML configuration files. The int-jpa namespace offers four main elements corresponding to the four primary JPA integration components.
Required Dependencies:
spring-integration-jpa (this package)spring-integration-core is requiredEntityManagerFactory, EntityManager, or JpaOperations bean must be configuredDefault Behaviors:
auto-startup="true" (components start automatically)persist-mode="MERGE" (for outbound components)flush="false", flush-size="0", clear-on-flush="false"expect-single-result="false", max-results="0" (unlimited)delete-after-poll="false", delete-in-batch="false"use-payload-as-parameter-source="false"reply-timeout="30000" (30 seconds for gateways)requires-reply="true" (gateways require reply)Threading Model:
Lifecycle:
auto-startup="true" starts components automatically (default)Exceptions:
Edge Cases:
entity-class, jpa-query, native-query, or named-queryentity-class for result type mapping@NamedQuery annotation<int:poller> child element)<int-jpa:transactional> child element<int-jpa:parameter> child elements"true" or "false" (case-sensitive)<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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/jpa
https://www.springframework.org/schema/integration/jpa/spring-integration-jpa.xsd">
<!-- JPA components here -->
</beans><int-jpa:inbound-channel-adapter
id="adapterId"
channel="outputChannel"
entity-manager-factory="entityManagerFactory"
entity-manager="entityManager"
jpa-operations="jpaOperations"
entity-class="com.example.Student"
jpa-query="SELECT s FROM Student s"
native-query="SELECT * FROM students"
named-query="Student.findAll"
delete-after-poll="false"
delete-in-batch="false"
flush="false"
expect-single-result="false"
max-results="0"
max-results-expression="headers.limit"
parameter-source-factory="paramSourceFactory"
auto-startup="true">
<int-jpa:parameter name="paramName" value="staticValue"/>
<int-jpa:parameter name="paramName" expression="payload.property"/>
<int-jpa:transactional .../>
<int:poller .../>
</int-jpa:inbound-channel-adapter><int-jpa:outbound-channel-adapter
id="adapterId"
channel="inputChannel"
entity-manager-factory="entityManagerFactory"
entity-manager="entityManager"
jpa-operations="jpaOperations"
entity-class="com.example.Student"
jpa-query="UPDATE Student s SET s.status = :status"
native-query="UPDATE students SET status = :status"
named-query="Student.updateStatus"
persist-mode="MERGE"
flush="false"
flush-size="0"
clear-on-flush="false"
parameter-source-factory="paramSourceFactory"
use-payload-as-parameter-source="false"
auto-startup="true"
order="0">
<int-jpa:parameter name="paramName" value="staticValue"/>
<int-jpa:parameter name="paramName" expression="payload.property"/>
<int-jpa:transactional .../>
</int-jpa:outbound-channel-adapter><int-jpa:retrieving-outbound-gateway
id="gatewayId"
request-channel="requestChannel"
reply-channel="replyChannel"
entity-manager-factory="entityManagerFactory"
entity-manager="entityManager"
jpa-operations="jpaOperations"
entity-class="com.example.Student"
jpa-query="SELECT s FROM Student s WHERE s.id = :id"
native-query="SELECT * FROM students WHERE id = :id"
named-query="Student.findById"
id-expression="payload"
expect-single-result="false"
first-result="0"
first-result-expression="payload.offset"
max-results="0"
max-results-expression="payload.limit"
delete-after-poll="false"
delete-in-batch="false"
flush="false"
parameter-source-factory="paramSourceFactory"
use-payload-as-parameter-source="false"
reply-timeout="30000"
requires-reply="true"
auto-startup="true"
order="0">
<int-jpa:parameter name="paramName" value="staticValue"/>
<int-jpa:parameter name="paramName" expression="payload.property"/>
<int-jpa:transactional .../>
</int-jpa:retrieving-outbound-gateway><int-jpa:updating-outbound-gateway
id="gatewayId"
request-channel="requestChannel"
reply-channel="replyChannel"
entity-manager-factory="entityManagerFactory"
entity-manager="entityManager"
jpa-operations="jpaOperations"
entity-class="com.example.Student"
jpa-query="UPDATE Student s SET s.status = :status WHERE s.id = :id"
native-query="UPDATE students SET status = :status WHERE id = :id"
named-query="Student.updateStatus"
persist-mode="MERGE"
flush="false"
flush-size="0"
clear-on-flush="false"
parameter-source-factory="paramSourceFactory"
use-payload-as-parameter-source="false"
reply-timeout="30000"
requires-reply="true"
auto-startup="true"
order="0">
<int-jpa:parameter name="paramName" value="staticValue"/>
<int-jpa:parameter name="paramName" expression="payload.property"/>
<int-jpa:transactional .../>
</int-jpa:updating-outbound-gateway><int-jpa:inbound-channel-adapter
id="studentInboundAdapter"
entity-manager-factory="entityManagerFactory"
channel="studentChannel"
entity-class="com.example.Student"
max-results="100">
<int:poller fixed-delay="10000"/>
</int-jpa:inbound-channel-adapter><int-jpa:inbound-channel-adapter
entity-manager-factory="entityManagerFactory"
channel="activeStudentChannel"
jpa-query="SELECT s FROM Student s WHERE s.status = 'ACTIVE'"
max-results="50">
<int:poller fixed-rate="30000"/>
</int-jpa:inbound-channel-adapter><int-jpa:inbound-channel-adapter
entity-manager-factory="entityManagerFactory"
channel="recentStudentChannel"
native-query="SELECT * FROM students WHERE registration_date > CURRENT_DATE - 7"
entity-class="com.example.Student">
<int:poller fixed-delay="60000"/>
</int-jpa:inbound-channel-adapter><int-jpa:inbound-channel-adapter
entity-manager-factory="entityManagerFactory"
channel="gradeAStudentChannel"
named-query="Student.findByGrade">
<int-jpa:parameter name="grade" value="A"/>
<int:poller fixed-delay="15000"/>
</int-jpa:inbound-channel-adapter><int-jpa:inbound-channel-adapter
entity-manager-factory="entityManagerFactory"
channel="processedOrderChannel"
jpa-query="SELECT o FROM ProcessedOrder o WHERE o.processed = true"
delete-after-poll="true"
delete-in-batch="true"
flush="true"
max-results="500">
<int:poller fixed-delay="5000"/>
</int-jpa:inbound-channel-adapter><int-jpa:inbound-channel-adapter
entity-manager-factory="entityManagerFactory"
channel="dynamicPollChannel"
jpa-query="SELECT t FROM Task t WHERE t.priority >= :minPriority"
parameter-source-factory="taskParameterSourceFactory"
max-results-expression="@config.batchSize">
<int:poller fixed-delay="10000"/>
</int-jpa:inbound-channel-adapter>
<bean id="taskParameterSourceFactory"
class="org.springframework.integration.jpa.support.parametersource.BeanPropertyParameterSourceFactory">
<property name="staticParameters">
<map>
<entry key="minPriority" value="5"/>
</map>
</property>
</bean><int-jpa:outbound-channel-adapter
channel="newStudentChannel"
entity-manager-factory="entityManagerFactory"
entity-class="com.example.Student"
persist-mode="PERSIST"/><int-jpa:outbound-channel-adapter
channel="updateStudentChannel"
entity-manager-factory="entityManagerFactory"
entity-class="com.example.Student"
persist-mode="MERGE"
flush="true"/><int-jpa:outbound-channel-adapter
channel="deleteStudentChannel"
entity-manager-factory="entityManagerFactory"
entity-class="com.example.Student"
persist-mode="DELETE"/><int-jpa:outbound-channel-adapter
channel="bulkUpdateChannel"
entity-manager-factory="entityManagerFactory"
jpa-query="UPDATE Student s SET s.status = :status WHERE s.year = :year">
<int-jpa:parameter name="status" expression="payload.newStatus"/>
<int-jpa:parameter name="year" expression="payload.year"/>
</int-jpa:outbound-channel-adapter><int-jpa:outbound-channel-adapter
channel="batchInsertChannel"
entity-manager-factory="entityManagerFactory"
entity-class="com.example.LogEntry"
persist-mode="PERSIST"
flush-size="100"
clear-on-flush="true"/><int-jpa:retrieving-outbound-gateway
request-channel="findStudentChannel"
reply-channel="studentResultChannel"
entity-manager-factory="entityManagerFactory"
entity-class="com.example.Student"
id-expression="payload"
expect-single-result="true"/><int-jpa:retrieving-outbound-gateway
request-channel="searchChannel"
reply-channel="resultsChannel"
entity-manager-factory="entityManagerFactory"
jpa-query="SELECT s FROM Student s WHERE s.lastName = :lastName">
<int-jpa:parameter name="lastName" expression="payload"/>
</int-jpa:retrieving-outbound-gateway><int-jpa:retrieving-outbound-gateway
request-channel="paginationChannel"
reply-channel="pageResultsChannel"
entity-manager-factory="entityManagerFactory"
entity-class="com.example.Student"
first-result-expression="payload.offset"
max-results-expression="payload.limit"/><int-jpa:retrieving-outbound-gateway
request-channel="complexSearchChannel"
reply-channel="searchResultsChannel"
entity-manager-factory="entityManagerFactory"
jpa-query="SELECT s FROM Student s WHERE s.department = :dept AND s.year = :year AND s.gpa >= :minGpa"
parameter-source-factory="beanPropertyParameterSourceFactory"
use-payload-as-parameter-source="true"
max-results-expression="payload.limit"/><int-jpa:retrieving-outbound-gateway
request-channel="retrieveAndDeleteChannel"
reply-channel="retrievedChannel"
entity-manager-factory="entityManagerFactory"
entity-class="com.example.Task"
id-expression="payload"
delete-after-poll="true"
expect-single-result="true"/><int-jpa:updating-outbound-gateway
request-channel="createChannel"
reply-channel="createdChannel"
entity-manager-factory="entityManagerFactory"
entity-class="com.example.Student"
persist-mode="PERSIST"/><int-jpa:updating-outbound-gateway
request-channel="updateChannel"
reply-channel="updatedChannel"
entity-manager-factory="entityManagerFactory"
entity-class="com.example.Student"
persist-mode="MERGE"
flush="true"/><int-jpa:updating-outbound-gateway
request-channel="bulkUpdateChannel"
reply-channel="updateCountChannel"
entity-manager-factory="entityManagerFactory"
jpa-query="UPDATE Student s SET s.graduated = true WHERE s.credits >= :requiredCredits">
<int-jpa:parameter name="requiredCredits" expression="payload"/>
</int-jpa:updating-outbound-gateway><int-jpa:updating-outbound-gateway
request-channel="namedUpdateChannel"
reply-channel="updateResultChannel"
entity-manager-factory="entityManagerFactory"
named-query="Student.updateStatus"
parameter-source-factory="beanPropertyParameterSourceFactory"
use-payload-as-parameter-source="true"/><int-jpa:parameter name="status" value="ACTIVE"/>
<int-jpa:parameter name="year" value="2024"/>
<int-jpa:parameter name="minGpa" value="3.0"/><int-jpa:parameter name="studentId" expression="payload"/>
<int-jpa:parameter name="department" expression="payload.department"/>
<int-jpa:parameter name="year" expression="headers['academicYear']"/>
<int-jpa:parameter name="fullName" expression="payload.firstName + ' ' + payload.lastName"/><int-jpa:retrieving-outbound-gateway
request-channel="searchChannel"
reply-channel="resultsChannel"
entity-manager-factory="entityManagerFactory"
jpa-query="SELECT s FROM Student s WHERE s.lastName = :lastName AND s.department = :department"
parameter-source-factory="paramSourceFactory"
use-payload-as-parameter-source="true"/>
<bean id="paramSourceFactory"
class="org.springframework.integration.jpa.support.parametersource.BeanPropertyParameterSourceFactory">
<property name="staticParameters">
<map>
<entry key="status" value="ACTIVE"/>
</map>
</property>
</bean><bean id="expressionParamFactory"
class="org.springframework.integration.jpa.support.parametersource.ExpressionEvaluatingParameterSourceFactory">
<constructor-arg ref="beanFactory"/>
<property name="parameters">
<map>
<entry key="searchTerm" value="payload.search"/>
<entry key="searchPattern" value="'%' + payload.search + '%'"/>
<entry key="startDate" value="T(java.time.LocalDate).now().minusMonths(1)"/>
</map>
</property>
</bean><int-jpa:inbound-channel-adapter
entity-manager-factory="entityManagerFactory"
channel="orderChannel"
entity-class="com.example.Order"
delete-after-poll="true">
<int:poller fixed-delay="5000">
<int:transactional transaction-manager="transactionManager"/>
</int:poller>
</int-jpa:inbound-channel-adapter><int-jpa:updating-outbound-gateway
request-channel="updateChannel"
reply-channel="updatedChannel"
entity-manager-factory="entityManagerFactory"
entity-class="com.example.Student"
persist-mode="MERGE">
<int-jpa:transactional
transaction-manager="transactionManager"
propagation="REQUIRED"
isolation="READ_COMMITTED"
timeout="30"
read-only="false"/>
</int-jpa:updating-outbound-gateway><bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.example.domain"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
</bean>
<int-jpa:inbound-channel-adapter
entity-manager-factory="entityManagerFactory"
channel="outputChannel"
entity-class="com.example.Student">
<int:poller fixed-delay="10000"/>
</int-jpa:inbound-channel-adapter><bean id="entityManager"
factory-bean="entityManagerFactory"
factory-method="createEntityManager"/>
<int-jpa:inbound-channel-adapter
entity-manager="entityManager"
channel="outputChannel"
entity-class="com.example.Student">
<int:poller fixed-delay="10000"/>
</int-jpa:inbound-channel-adapter><bean id="jpaOperations"
class="org.springframework.integration.jpa.core.DefaultJpaOperations">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<int-jpa:inbound-channel-adapter
jpa-operations="jpaOperations"
channel="outputChannel"
entity-class="com.example.Student">
<int:poller fixed-delay="10000"/>
</int-jpa:inbound-channel-adapter><?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/jpa
https://www.springframework.org/schema/integration/jpa/spring-integration-jpa.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- Enable annotation configuration -->
<context:component-scan base-package="com.example"/>
<context:annotation-config/>
<!-- Data source -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- Entity manager factory -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.example.domain"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
</bean>
</property>
</bean>
<!-- Transaction manager -->
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- Message channels -->
<int:channel id="studentInputChannel"/>
<int:channel id="studentOutputChannel"/>
<int:channel id="findStudentChannel"/>
<int:channel id="studentResultChannel"/>
<!-- Inbound adapter - poll students -->
<int-jpa:inbound-channel-adapter
id="studentInboundAdapter"
entity-manager-factory="entityManagerFactory"
channel="studentOutputChannel"
entity-class="com.example.domain.Student"
max-results="100"
delete-after-poll="true">
<int:poller fixed-delay="10000">
<int:transactional transaction-manager="transactionManager"/>
</int:poller>
</int-jpa:inbound-channel-adapter>
<!-- Outbound adapter - persist students -->
<int-jpa:outbound-channel-adapter
id="studentOutboundAdapter"
channel="studentInputChannel"
entity-manager-factory="entityManagerFactory"
entity-class="com.example.domain.Student"
persist-mode="MERGE">
<int-jpa:transactional transaction-manager="transactionManager"/>
</int-jpa:outbound-channel-adapter>
<!-- Retrieving gateway - find student by ID -->
<int-jpa:retrieving-outbound-gateway
id="findStudentGateway"
request-channel="findStudentChannel"
reply-channel="studentResultChannel"
entity-manager-factory="entityManagerFactory"
entity-class="com.example.domain.Student"
id-expression="payload"
expect-single-result="true">
<int-jpa:transactional transaction-manager="transactionManager"/>
</int-jpa:retrieving-outbound-gateway>
</beans>XML configuration equivalent of Java DSL:
Java DSL:
Jpa.inboundAdapter(entityManagerFactory)
.entityClass(Student.class)
.maxResults(100)
.deleteAfterPoll(true)XML:
<int-jpa:inbound-channel-adapter
entity-manager-factory="entityManagerFactory"
channel="outputChannel"
entity-class="com.example.Student"
max-results="100"
delete-after-poll="true">
<int:poller fixed-delay="10000"/>
</int-jpa:inbound-channel-adapter>