Add Coroutines support to Spring AOP

This commit adds support for Kotlin Coroutines to Spring AOP
by leveraging CoroutinesUtils#invokeSuspendingFunction in
AopUtils#invokeJoinpointUsingReflection to convert it to the
equivalent Publisher return value, like in other parts of Spring
Framework.

That allows method interceptors with Reactive support to process
related return values.

CglibAopProxy#processReturnType and JdkDynamicAopProxy#invoke
take care of the conversion from the Publisher return value
to Kotlin Coroutines.

Reactive transactional and HTTP service interface support
have been refined to leverage those new generic capabilities.

Closes gh-22462
This commit is contained in:
Sébastien Deleuze
2023-08-24 22:09:19 +02:00
parent 9b3f4567ee
commit c8169e5cad
11 changed files with 278 additions and 51 deletions

View File

@@ -26,8 +26,6 @@ import io.vavr.control.Try;
import kotlin.coroutines.Continuation;
import kotlin.coroutines.CoroutineContext;
import kotlinx.coroutines.Job;
import kotlinx.coroutines.reactive.ReactiveFlowKt;
import kotlinx.coroutines.reactor.MonoKt;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.reactivestreams.Publisher;
@@ -370,12 +368,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
if (corInv != null) {
callback = () -> KotlinDelegate.invokeSuspendingFunction(method, corInv);
}
Object result = txSupport.invokeWithinTransaction(method, targetClass, callback, txAttr, rtm);
if (corInv != null) {
return (hasSuspendingFlowReturnType ? KotlinDelegate.asFlow((Publisher<?>) result) :
KotlinDelegate.awaitSingleOrNull((Mono<?>) result, corInv.getContinuation()));
}
return result;
return txSupport.invokeWithinTransaction(method, targetClass, callback, txAttr, rtm);
}
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
@@ -896,16 +889,6 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
*/
private static class KotlinDelegate {
private static Object asFlow(Publisher<?> publisher) {
return ReactiveFlowKt.asFlow(publisher);
}
@SuppressWarnings("unchecked")
@Nullable
private static Object awaitSingleOrNull(Mono<?> publisher, Object continuation) {
return MonoKt.awaitSingleOrNull(publisher, (Continuation<Object>) continuation);
}
public static Publisher<?> invokeSuspendingFunction(Method method, CoroutinesInvocationCallback callback) {
CoroutineContext coroutineContext = ((Continuation<?>) callback.getContinuation()).getContext().minusKey(Job.Key);
return CoroutinesUtils.invokeSuspendingFunction(coroutineContext, method, callback.getTarget(), callback.getArguments());