@@ -173,7 +173,11 @@ public static TransactionStatus currentTransactionStatus() throws NoTransactionE
173173 @ Nullable
174174 private BeanFactory beanFactory ;
175175
176- private final ConcurrentMap <Object , Object > transactionManagerCache = new ConcurrentReferenceHashMap <>(4 );
176+ private final ConcurrentMap <Object , TransactionManager > transactionManagerCache =
177+ new ConcurrentReferenceHashMap <>(4 );
178+
179+ private final ConcurrentMap <Method , ReactiveTransactionSupport > transactionSupportCache =
180+ new ConcurrentReferenceHashMap <>(1024 );
177181
178182
179183 protected TransactionAspectSupport () {
@@ -301,7 +305,7 @@ public void afterPropertiesSet() {
301305 if (getTransactionManager () == null && this .beanFactory == null ) {
302306 throw new IllegalStateException (
303307 "Set the 'transactionManager' property or make sure to run within a BeanFactory " +
304- "containing a PlatformTransactionManager bean!" );
308+ "containing a TransactionManager bean!" );
305309 }
306310 if (getTransactionAttributeSource () == null ) {
307311 throw new IllegalStateException (
@@ -325,26 +329,35 @@ public void afterPropertiesSet() {
325329 protected Object invokeWithinTransaction (Method method , @ Nullable Class <?> targetClass ,
326330 final InvocationCallback invocation ) throws Throwable {
327331
328- if (this .reactiveAdapterRegistry != null ) {
329- if (KotlinDetector .isKotlinType (method .getDeclaringClass ()) && KotlinDelegate .isSuspend (method )) {
330- throw new TransactionUsageException ("Unsupported annotated transaction on suspending function detected: "
331- + method + ". Use TransactionalOperator.transactional extensions instead." );
332- }
333- ReactiveAdapter adapter = this .reactiveAdapterRegistry .getAdapter (method .getReturnType ());
334- if (adapter != null ) {
335- return new ReactiveTransactionSupport (adapter ).invokeWithinTransaction (method , targetClass , invocation );
336- }
337- }
338-
339332 // If the transaction attribute is null, the method is non-transactional.
340333 TransactionAttributeSource tas = getTransactionAttributeSource ();
341334 final TransactionAttribute txAttr = (tas != null ? tas .getTransactionAttribute (method , targetClass ) : null );
342- final PlatformTransactionManager tm = determineTransactionManager (txAttr );
335+ final TransactionManager tm = determineTransactionManager (txAttr );
336+
337+ if (this .reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager ) {
338+ ReactiveTransactionSupport txSupport = this .transactionSupportCache .computeIfAbsent (method , key -> {
339+ if (KotlinDetector .isKotlinType (method .getDeclaringClass ()) && KotlinDelegate .isSuspend (method )) {
340+ throw new TransactionUsageException (
341+ "Unsupported annotated transaction on suspending function detected: " + method +
342+ ". Use TransactionalOperator.transactional extensions instead." );
343+ }
344+ ReactiveAdapter adapter = this .reactiveAdapterRegistry .getAdapter (method .getReturnType ());
345+ if (adapter == null ) {
346+ throw new IllegalStateException ("Cannot apply reactive transaction to non-reactive return type: " +
347+ method .getReturnType ());
348+ }
349+ return new ReactiveTransactionSupport (adapter );
350+ });
351+ return txSupport .invokeWithinTransaction (
352+ method , targetClass , invocation , txAttr , (ReactiveTransactionManager ) tm );
353+ }
354+
355+ PlatformTransactionManager ptm = asPlatformTransactionManager (tm );
343356 final String joinpointIdentification = methodIdentification (method , targetClass , txAttr );
344357
345- if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager )) {
358+ if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager )) {
346359 // Standard transaction demarcation with getTransaction and commit/rollback calls.
347- TransactionInfo txInfo = createTransactionIfNecessary (tm , txAttr , joinpointIdentification );
360+ TransactionInfo txInfo = createTransactionIfNecessary (ptm , txAttr , joinpointIdentification );
348361
349362 Object retVal ;
350363 try {
@@ -378,8 +391,8 @@ protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targe
378391
379392 // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
380393 try {
381- Object result = ((CallbackPreferringPlatformTransactionManager ) tm ).execute (txAttr , status -> {
382- TransactionInfo txInfo = prepareTransactionInfo (tm , txAttr , joinpointIdentification , status );
394+ Object result = ((CallbackPreferringPlatformTransactionManager ) ptm ).execute (txAttr , status -> {
395+ TransactionInfo txInfo = prepareTransactionInfo (ptm , txAttr , joinpointIdentification , status );
383396 try {
384397 Object retVal = invocation .proceedWithInvocation ();
385398 if (vavrPresent && VavrDelegate .isVavrTry (retVal )) {
@@ -446,10 +459,10 @@ protected void clearTransactionManagerCache() {
446459 * Determine the specific transaction manager to use for the given transaction.
447460 */
448461 @ Nullable
449- protected PlatformTransactionManager determineTransactionManager (@ Nullable TransactionAttribute txAttr ) {
462+ protected TransactionManager determineTransactionManager (@ Nullable TransactionAttribute txAttr ) {
450463 // Do not attempt to lookup tx manager if no tx attributes are set
451464 if (txAttr == null || this .beanFactory == null ) {
452- return asPlatformTransactionManager ( getTransactionManager () );
465+ return getTransactionManager ();
453466 }
454467
455468 String qualifier = txAttr .getQualifier ();
@@ -460,12 +473,11 @@ else if (StringUtils.hasText(this.transactionManagerBeanName)) {
460473 return determineQualifiedTransactionManager (this .beanFactory , this .transactionManagerBeanName );
461474 }
462475 else {
463- PlatformTransactionManager defaultTransactionManager = asPlatformTransactionManager ( getTransactionManager () );
476+ TransactionManager defaultTransactionManager = getTransactionManager ();
464477 if (defaultTransactionManager == null ) {
465- defaultTransactionManager = asPlatformTransactionManager (
466- this .transactionManagerCache .get (DEFAULT_TRANSACTION_MANAGER_KEY ));
478+ defaultTransactionManager = this .transactionManagerCache .get (DEFAULT_TRANSACTION_MANAGER_KEY );
467479 if (defaultTransactionManager == null ) {
468- defaultTransactionManager = this .beanFactory .getBean (PlatformTransactionManager .class );
480+ defaultTransactionManager = this .beanFactory .getBean (TransactionManager .class );
469481 this .transactionManagerCache .putIfAbsent (
470482 DEFAULT_TRANSACTION_MANAGER_KEY , defaultTransactionManager );
471483 }
@@ -474,11 +486,11 @@ else if (StringUtils.hasText(this.transactionManagerBeanName)) {
474486 }
475487 }
476488
477- private PlatformTransactionManager determineQualifiedTransactionManager (BeanFactory beanFactory , String qualifier ) {
478- PlatformTransactionManager txManager = asPlatformTransactionManager ( this .transactionManagerCache .get (qualifier ) );
489+ private TransactionManager determineQualifiedTransactionManager (BeanFactory beanFactory , String qualifier ) {
490+ TransactionManager txManager = this .transactionManagerCache .get (qualifier );
479491 if (txManager == null ) {
480492 txManager = BeanFactoryAnnotationUtils .qualifiedBeanOfType (
481- beanFactory , PlatformTransactionManager .class , qualifier );
493+ beanFactory , TransactionManager .class , qualifier );
482494 this .transactionManagerCache .putIfAbsent (qualifier , txManager );
483495 }
484496 return txManager ;
@@ -841,33 +853,30 @@ public ReactiveTransactionSupport(ReactiveAdapter adapter) {
841853 this .adapter = adapter ;
842854 }
843855
844- public Object invokeWithinTransaction (Method method , @ Nullable Class <?> targetClass , InvocationCallback invocation ) {
845- // If the transaction attribute is null, the method is non-transactional.
846- TransactionAttributeSource tas = getTransactionAttributeSource ();
847- TransactionAttribute txAttr = (tas != null ? tas .getTransactionAttribute (method , targetClass ) : null );
848- ReactiveTransactionManager tm = determineTransactionManager (txAttr );
856+ public Object invokeWithinTransaction (Method method , @ Nullable Class <?> targetClass ,
857+ InvocationCallback invocation , @ Nullable TransactionAttribute txAttr , ReactiveTransactionManager rtm ) {
858+
849859 String joinpointIdentification = methodIdentification (method , targetClass , txAttr );
850860
851861 // Optimize for Mono
852862 if (Mono .class .isAssignableFrom (method .getReturnType ())) {
853863 return TransactionContextManager .currentContext ().flatMap (context ->
854- createTransactionIfNecessary (tm , txAttr , joinpointIdentification ).flatMap (it -> {
864+ createTransactionIfNecessary (rtm , txAttr , joinpointIdentification ).flatMap (it -> {
855865 try {
856866 // Need re-wrapping until we get hold of the exception through usingWhen.
857- return Mono
858- .<Object , ReactiveTransactionInfo >usingWhen (
859- Mono .just (it ),
860- txInfo -> {
861- try {
862- return (Mono <?>) invocation .proceedWithInvocation ();
863- }
864- catch (Throwable ex ) {
865- return Mono .error (ex );
866- }
867- },
868- this ::commitTransactionAfterReturning ,
869- (txInfo , err ) -> Mono .empty (),
870- this ::commitTransactionAfterReturning )
867+ return Mono .<Object , ReactiveTransactionInfo >usingWhen (
868+ Mono .just (it ),
869+ txInfo -> {
870+ try {
871+ return (Mono <?>) invocation .proceedWithInvocation ();
872+ }
873+ catch (Throwable ex ) {
874+ return Mono .error (ex );
875+ }
876+ },
877+ this ::commitTransactionAfterReturning ,
878+ (txInfo , err ) -> Mono .empty (),
879+ this ::commitTransactionAfterReturning )
871880 .onErrorResume (ex ->
872881 completeTransactionAfterThrowing (it , ex ).then (Mono .error (ex )));
873882 }
@@ -881,7 +890,7 @@ public Object invokeWithinTransaction(Method method, @Nullable Class<?> targetCl
881890
882891 // Any other reactive type, typically a Flux
883892 return this .adapter .fromPublisher (TransactionContextManager .currentContext ().flatMapMany (context ->
884- createTransactionIfNecessary (tm , txAttr , joinpointIdentification ).flatMapMany (it -> {
893+ createTransactionIfNecessary (rtm , txAttr , joinpointIdentification ).flatMapMany (it -> {
885894 try {
886895 // Need re-wrapping until we get hold of the exception through usingWhen.
887896 return Flux
@@ -909,58 +918,8 @@ public Object invokeWithinTransaction(Method method, @Nullable Class<?> targetCl
909918 .subscriberContext (TransactionContextManager .getOrCreateContextHolder ()));
910919 }
911920
912- @ Nullable
913- private ReactiveTransactionManager determineTransactionManager (@ Nullable TransactionAttribute txAttr ) {
914- // Do not attempt to lookup tx manager if no tx attributes are set
915- if (txAttr == null || beanFactory == null ) {
916- return asReactiveTransactionManager (getTransactionManager ());
917- }
918-
919- String qualifier = txAttr .getQualifier ();
920- if (StringUtils .hasText (qualifier )) {
921- return determineQualifiedTransactionManager (beanFactory , qualifier );
922- }
923- else if (StringUtils .hasText (transactionManagerBeanName )) {
924- return determineQualifiedTransactionManager (beanFactory , transactionManagerBeanName );
925- }
926- else {
927- ReactiveTransactionManager defaultTransactionManager = asReactiveTransactionManager (getTransactionManager ());
928- if (defaultTransactionManager == null ) {
929- defaultTransactionManager = asReactiveTransactionManager (
930- transactionManagerCache .get (DEFAULT_TRANSACTION_MANAGER_KEY ));
931- if (defaultTransactionManager == null ) {
932- defaultTransactionManager = beanFactory .getBean (ReactiveTransactionManager .class );
933- transactionManagerCache .putIfAbsent (
934- DEFAULT_TRANSACTION_MANAGER_KEY , defaultTransactionManager );
935- }
936- }
937- return defaultTransactionManager ;
938- }
939- }
940-
941- private ReactiveTransactionManager determineQualifiedTransactionManager (BeanFactory beanFactory , String qualifier ) {
942- ReactiveTransactionManager txManager = asReactiveTransactionManager (transactionManagerCache .get (qualifier ));
943- if (txManager == null ) {
944- txManager = BeanFactoryAnnotationUtils .qualifiedBeanOfType (
945- beanFactory , ReactiveTransactionManager .class , qualifier );
946- transactionManagerCache .putIfAbsent (qualifier , txManager );
947- }
948- return txManager ;
949- }
950-
951- @ Nullable
952- private ReactiveTransactionManager asReactiveTransactionManager (@ Nullable Object transactionManager ) {
953- if (transactionManager == null || transactionManager instanceof ReactiveTransactionManager ) {
954- return (ReactiveTransactionManager ) transactionManager ;
955- }
956- else {
957- throw new IllegalStateException (
958- "Specified transaction manager is not a ReactiveTransactionManager: " + transactionManager );
959- }
960- }
961-
962921 @ SuppressWarnings ("serial" )
963- private Mono <ReactiveTransactionInfo > createTransactionIfNecessary (@ Nullable ReactiveTransactionManager tm ,
922+ private Mono <ReactiveTransactionInfo > createTransactionIfNecessary (ReactiveTransactionManager tm ,
964923 @ Nullable TransactionAttribute txAttr , final String joinpointIdentification ) {
965924
966925 // If no name specified, apply method identification as transaction name.
@@ -972,21 +931,9 @@ public String getName() {
972931 }
973932 };
974933 }
975- TransactionAttribute attrToUse = txAttr ;
976-
977- Mono <ReactiveTransaction > tx = Mono .empty ();
978- if (txAttr != null ) {
979- if (tm != null ) {
980- tx = tm .getReactiveTransaction (txAttr );
981- }
982- else {
983- if (logger .isDebugEnabled ()) {
984- logger .debug ("Skipping transactional joinpoint [" + joinpointIdentification +
985- "] because no transaction manager has been configured" );
986- }
987- }
988- }
989934
935+ final TransactionAttribute attrToUse = txAttr ;
936+ Mono <ReactiveTransaction > tx = (attrToUse != null ? tm .getReactiveTransaction (attrToUse ) : Mono .empty ());
990937 return tx .map (it -> prepareTransactionInfo (tm , attrToUse , joinpointIdentification , it )).switchIfEmpty (
991938 Mono .defer (() -> Mono .just (prepareTransactionInfo (tm , attrToUse , joinpointIdentification , null ))));
992939 }
0 commit comments