Add Reactive TX Manager support (#3201)
* Add Reactive TX Manager support * Change `TransactionInterceptorBuilder` and `TransactionHandleMessageAdvice` to reply on a generic `TransactionManager`, so we can configure reactive one as well * Change a `<transactional>` XML element to support a generic `TransactionManager` reference, so we can configure reactive one as well * Support `adviceChain` configuration for the `ReactiveMessageHandler` in the `ConsumerEndpointFactoryBean` * Attemp to apply reactive transaction for the Reactive MongoDB channel adapter * * Revert `MongoDbTests` change - to support transactions we need the latest MongoDb server with replica enabled * Document reactive transactions * * Address PR reviews
This commit is contained in:
@@ -200,10 +200,12 @@ public class ConsumerEndpointFactoryBean
|
||||
}
|
||||
|
||||
if (!(this.handler instanceof ReactiveMessageHandlerAdapter)) {
|
||||
adviceChain();
|
||||
this.handler = adviceChain(this.handler);
|
||||
}
|
||||
else if (!CollectionUtils.isEmpty(this.adviceChain)) {
|
||||
LOGGER.warn("the advice chain cannot be applied to a 'ReactiveMessageHandler'");
|
||||
this.handler =
|
||||
new ReactiveMessageHandlerAdapter(
|
||||
adviceChain(((ReactiveMessageHandlerAdapter) this.handler).getDelegate()));
|
||||
}
|
||||
if (this.channelResolver == null) {
|
||||
this.channelResolver = ChannelResolverUtils.getChannelResolver(this.beanFactory);
|
||||
@@ -234,7 +236,9 @@ public class ConsumerEndpointFactoryBean
|
||||
}
|
||||
}
|
||||
|
||||
private void adviceChain() {
|
||||
@SuppressWarnings("unchecked")
|
||||
private <H> H adviceChain(H handler) {
|
||||
H theHandler = handler;
|
||||
if (!CollectionUtils.isEmpty(this.adviceChain)) {
|
||||
/*
|
||||
* ARPMHs advise the handleRequestMessage method internally and already have the advice chain injected.
|
||||
@@ -243,24 +247,25 @@ public class ConsumerEndpointFactoryBean
|
||||
* If the handler is already advised,
|
||||
* add the configured advices to its chain, otherwise create a proxy.
|
||||
*/
|
||||
Class<?> targetClass = AopUtils.getTargetClass(this.handler);
|
||||
Class<?> targetClass = AopUtils.getTargetClass(theHandler);
|
||||
boolean replyMessageHandler = AbstractReplyProducingMessageHandler.class.isAssignableFrom(targetClass);
|
||||
|
||||
for (Advice advice : this.adviceChain) {
|
||||
if (!replyMessageHandler || advice instanceof HandleMessageAdvice) {
|
||||
NameMatchMethodPointcutAdvisor handlerAdvice = new NameMatchMethodPointcutAdvisor(advice);
|
||||
handlerAdvice.addMethodName("handleMessage");
|
||||
if (this.handler instanceof Advised) {
|
||||
((Advised) this.handler).addAdvisor(handlerAdvice);
|
||||
if (theHandler instanceof Advised) {
|
||||
((Advised) theHandler).addAdvisor(handlerAdvice);
|
||||
}
|
||||
else {
|
||||
ProxyFactory proxyFactory = new ProxyFactory(this.handler);
|
||||
ProxyFactory proxyFactory = new ProxyFactory(theHandler);
|
||||
proxyFactory.addAdvisor(handlerAdvice);
|
||||
this.handler = (MessageHandler) proxyFactory.getProxy(this.beanClassLoader);
|
||||
theHandler = (H) proxyFactory.getProxy(this.beanClassLoader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return theHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,7 +31,7 @@ import org.springframework.integration.scheduling.PollerMetadata;
|
||||
import org.springframework.integration.transaction.TransactionInterceptorBuilder;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionManager;
|
||||
import org.springframework.transaction.interceptor.TransactionInterceptor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -112,10 +112,10 @@ public abstract class ConsumerEndpointSpec<S extends ConsumerEndpointSpec<S, H>,
|
||||
* {@code PlatformTransactionManager} and default
|
||||
* {@link org.springframework.transaction.interceptor.DefaultTransactionAttribute}
|
||||
* for the {@link MessageHandler}.
|
||||
* @param transactionManager the {@link PlatformTransactionManager} to use.
|
||||
* @param transactionManager the {@link TransactionManager} to use.
|
||||
* @return the spec.
|
||||
*/
|
||||
public S transactional(PlatformTransactionManager transactionManager) {
|
||||
public S transactional(TransactionManager transactionManager) {
|
||||
return transactional(transactionManager, false);
|
||||
}
|
||||
|
||||
@@ -124,14 +124,14 @@ public abstract class ConsumerEndpointSpec<S extends ConsumerEndpointSpec<S, H>,
|
||||
* {@code PlatformTransactionManager} and default
|
||||
* {@link org.springframework.transaction.interceptor.DefaultTransactionAttribute}
|
||||
* for the {@link MessageHandler}.
|
||||
* @param transactionManager the {@link PlatformTransactionManager} to use.
|
||||
* @param transactionManager the {@link TransactionManager} to use.
|
||||
* @param handleMessageAdvice the flag to indicate the target {@link Advice} type:
|
||||
* {@code false} - regular {@link TransactionInterceptor}; {@code true} -
|
||||
* {@link org.springframework.integration.transaction.TransactionHandleMessageAdvice}
|
||||
* extension.
|
||||
* @return the spec.
|
||||
*/
|
||||
public S transactional(PlatformTransactionManager transactionManager, boolean handleMessageAdvice) {
|
||||
public S transactional(TransactionManager transactionManager, boolean handleMessageAdvice) {
|
||||
return transactional(new TransactionInterceptorBuilder(handleMessageAdvice)
|
||||
.transactionManager(transactionManager)
|
||||
.build());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,7 +31,7 @@ import org.springframework.integration.transaction.TransactionInterceptorBuilder
|
||||
import org.springframework.integration.transaction.TransactionSynchronizationFactory;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.scheduling.Trigger;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionManager;
|
||||
import org.springframework.transaction.interceptor.TransactionInterceptor;
|
||||
import org.springframework.util.ErrorHandler;
|
||||
|
||||
@@ -147,10 +147,10 @@ public final class PollerSpec extends IntegrationComponentSpec<PollerSpec, Polle
|
||||
* provided {@code PlatformTransactionManager} and default
|
||||
* {@link org.springframework.transaction.interceptor.DefaultTransactionAttribute}
|
||||
* for the {@code pollingTask}.
|
||||
* @param transactionManager the {@link PlatformTransactionManager} to use.
|
||||
* @param transactionManager the {@link TransactionManager} to use.
|
||||
* @return the spec.
|
||||
*/
|
||||
public PollerSpec transactional(PlatformTransactionManager transactionManager) {
|
||||
public PollerSpec transactional(TransactionManager transactionManager) {
|
||||
return transactional(new TransactionInterceptorBuilder()
|
||||
.transactionManager(transactionManager)
|
||||
.build());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,7 +19,7 @@ package org.springframework.integration.transaction;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.integration.handler.advice.HandleMessageAdvice;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionManager;
|
||||
import org.springframework.transaction.interceptor.TransactionAttributeSource;
|
||||
import org.springframework.transaction.interceptor.TransactionInterceptor;
|
||||
|
||||
@@ -46,12 +46,16 @@ public class TransactionHandleMessageAdvice extends TransactionInterceptor imple
|
||||
public TransactionHandleMessageAdvice() {
|
||||
}
|
||||
|
||||
public TransactionHandleMessageAdvice(PlatformTransactionManager ptm, Properties attributes) {
|
||||
super(ptm, attributes);
|
||||
public TransactionHandleMessageAdvice(TransactionManager transactionManager, Properties transactionAttributes) {
|
||||
setTransactionManager(transactionManager);
|
||||
setTransactionAttributes(transactionAttributes);
|
||||
}
|
||||
|
||||
public TransactionHandleMessageAdvice(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
|
||||
super(ptm, tas);
|
||||
public TransactionHandleMessageAdvice(TransactionManager transactionManager,
|
||||
TransactionAttributeSource transactionAttributeSource) {
|
||||
|
||||
setTransactionManager(transactionManager);
|
||||
setTransactionAttributeSource(transactionAttributeSource);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package org.springframework.integration.transaction;
|
||||
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionManager;
|
||||
import org.springframework.transaction.annotation.Isolation;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
|
||||
@@ -29,8 +29,8 @@ import org.springframework.util.Assert;
|
||||
* Provides a fluent API to build a transaction interceptor. See
|
||||
* {@link TransactionAttribute} for property meanings; if a {@link TransactionAttribute}
|
||||
* is provided, the individual properties are ignored. If a
|
||||
* {@link PlatformTransactionManager} is not provided, a single instance of
|
||||
* {@link PlatformTransactionManager} will be discovered at runtime; if you have more
|
||||
* {@link TransactionManager} is not provided, a single instance of
|
||||
* {@link TransactionManager} will be discovered at runtime; if you have more
|
||||
* than one transaction manager, you must inject the one you want to use here.
|
||||
* <p>
|
||||
* When the {@code handleMessageAdvice} option is in use, this builder produces
|
||||
@@ -91,7 +91,7 @@ public class TransactionInterceptorBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public TransactionInterceptorBuilder transactionManager(PlatformTransactionManager transactionManager) {
|
||||
public TransactionInterceptorBuilder transactionManager(TransactionManager transactionManager) {
|
||||
this.transactionInterceptor.setTransactionManager(transactionManager);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -4155,21 +4155,21 @@
|
||||
<xsd:complexType name="transactionalType">
|
||||
<xsd:attribute name="transaction-manager" type="xsd:string" default="transactionManager">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The bean name of the PlatformTransactionManager to use.
|
||||
]]></xsd:documentation>
|
||||
<xsd:documentation>
|
||||
The bean name of the PlatformTransactionManager to use.
|
||||
</xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.transaction.PlatformTransactionManager"/>
|
||||
<tool:expected-type type="org.springframework.transaction.TransactionManager"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="propagation" default="REQUIRED">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:org.springframework.transaction.annotation.Propagation"><![CDATA[
|
||||
The transaction propagation behavior.
|
||||
]]></xsd:documentation>
|
||||
<xsd:documentation source="java:org.springframework.transaction.annotation.Propagation">
|
||||
The transaction propagation behavior.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:union memberTypes="propagationEnumeration xsd:string"/>
|
||||
@@ -4177,9 +4177,9 @@
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="isolation" default="DEFAULT">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:org.springframework.transaction.annotation.Isolation"><![CDATA[
|
||||
The transaction isolation level.
|
||||
]]></xsd:documentation>
|
||||
<xsd:documentation source="java:org.springframework.transaction.annotation.Isolation">
|
||||
The transaction isolation level.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:union memberTypes="isolationEnumeration xsd:string"/>
|
||||
@@ -4187,24 +4187,24 @@
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="timeout" type="xsd:string" default="-1">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The transaction timeout value (in seconds).
|
||||
]]></xsd:documentation>
|
||||
<xsd:documentation>
|
||||
The transaction timeout value (in seconds).
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="read-only" type="xsd:string" default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Is this transaction read-only?
|
||||
]]></xsd:documentation>
|
||||
<xsd:documentation>
|
||||
Is this transaction read-only?
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="synchronization-factory" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
<xsd:documentation>
|
||||
Reference to an instance of org.springframework.integration.transaction.TransactionSynchronizationFactory
|
||||
which will return an instance of org.springframework.transaction.support.TransactionSynchronization via its create(..) method.
|
||||
]]></xsd:documentation>
|
||||
</xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type
|
||||
|
||||
@@ -255,3 +255,12 @@ The following example shows how to do so:
|
||||
<bean id="transactionManager" class="o.s.i.transaction.PseudoTransactionManager" />
|
||||
----
|
||||
====
|
||||
|
||||
[[reactive-transactions]]
|
||||
=== Reactive Transactions
|
||||
|
||||
Starting with version 5.3, a `ReactiveTransactionManager` can also be used together with a `TransactionInterceptor` advice for endpoints returning a reactive type.
|
||||
This includes `MessageSource` and `ReactiveMessageHandler` implementations (e.g. `ReactiveMongoDbMessageSource`) which produce a message with a `Flux` or `Mono` payload.
|
||||
All other reply producing message handler implementations can rely on a `ReactiveTransactionManager` when their reply payload is also some reactive type.
|
||||
|
||||
|
||||
|
||||
@@ -57,6 +57,10 @@ A new `publishSubscribeChannel()` operator, based on the `BroadcastCapableChanne
|
||||
This fluent API has its advantage when we configure sub-flows as pub-sub subscribers for broker-backed channels like `SubscribableJmsChannel`, `SubscribableRedisChannel` etc.
|
||||
See <<./dsl.adoc#java-dsl-subflows,Sub-flows support>> for more information.
|
||||
|
||||
Transactional support in Spring Integration now also includes options to configure a `ReactiveTransactionManager` if a `MessageSource` or `MessageHandler` implementation produces a reactive type for payload to send.
|
||||
See `TransactionInterceptorBuilder` for more information.
|
||||
See also <<./transactions.adoc#reactive-transactions,Reactive Transactions>>.
|
||||
|
||||
[[x5.3-amqp]]
|
||||
=== AMQP Changes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user