@@ -173,7 +173,11 @@ public static TransactionStatus currentTransactionStatus() throws NoTransactionE
173
173
@ Nullable
174
174
private BeanFactory beanFactory ;
175
175
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 );
177
181
178
182
179
183
protected TransactionAspectSupport () {
@@ -301,7 +305,7 @@ public void afterPropertiesSet() {
301
305
if (getTransactionManager () == null && this .beanFactory == null ) {
302
306
throw new IllegalStateException (
303
307
"Set the 'transactionManager' property or make sure to run within a BeanFactory " +
304
- "containing a PlatformTransactionManager bean!" );
308
+ "containing a TransactionManager bean!" );
305
309
}
306
310
if (getTransactionAttributeSource () == null ) {
307
311
throw new IllegalStateException (
@@ -325,26 +329,35 @@ public void afterPropertiesSet() {
325
329
protected Object invokeWithinTransaction (Method method , @ Nullable Class <?> targetClass ,
326
330
final InvocationCallback invocation ) throws Throwable {
327
331
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
-
339
332
// If the transaction attribute is null, the method is non-transactional.
340
333
TransactionAttributeSource tas = getTransactionAttributeSource ();
341
334
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 );
343
356
final String joinpointIdentification = methodIdentification (method , targetClass , txAttr );
344
357
345
- if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager )) {
358
+ if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager )) {
346
359
// Standard transaction demarcation with getTransaction and commit/rollback calls.
347
- TransactionInfo txInfo = createTransactionIfNecessary (tm , txAttr , joinpointIdentification );
360
+ TransactionInfo txInfo = createTransactionIfNecessary (ptm , txAttr , joinpointIdentification );
348
361
349
362
Object retVal ;
350
363
try {
@@ -378,8 +391,8 @@ protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targe
378
391
379
392
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
380
393
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 );
383
396
try {
384
397
Object retVal = invocation .proceedWithInvocation ();
385
398
if (vavrPresent && VavrDelegate .isVavrTry (retVal )) {
@@ -446,10 +459,10 @@ protected void clearTransactionManagerCache() {
446
459
* Determine the specific transaction manager to use for the given transaction.
447
460
*/
448
461
@ Nullable
449
- protected PlatformTransactionManager determineTransactionManager (@ Nullable TransactionAttribute txAttr ) {
462
+ protected TransactionManager determineTransactionManager (@ Nullable TransactionAttribute txAttr ) {
450
463
// Do not attempt to lookup tx manager if no tx attributes are set
451
464
if (txAttr == null || this .beanFactory == null ) {
452
- return asPlatformTransactionManager ( getTransactionManager () );
465
+ return getTransactionManager ();
453
466
}
454
467
455
468
String qualifier = txAttr .getQualifier ();
@@ -460,12 +473,11 @@ else if (StringUtils.hasText(this.transactionManagerBeanName)) {
460
473
return determineQualifiedTransactionManager (this .beanFactory , this .transactionManagerBeanName );
461
474
}
462
475
else {
463
- PlatformTransactionManager defaultTransactionManager = asPlatformTransactionManager ( getTransactionManager () );
476
+ TransactionManager defaultTransactionManager = getTransactionManager ();
464
477
if (defaultTransactionManager == null ) {
465
- defaultTransactionManager = asPlatformTransactionManager (
466
- this .transactionManagerCache .get (DEFAULT_TRANSACTION_MANAGER_KEY ));
478
+ defaultTransactionManager = this .transactionManagerCache .get (DEFAULT_TRANSACTION_MANAGER_KEY );
467
479
if (defaultTransactionManager == null ) {
468
- defaultTransactionManager = this .beanFactory .getBean (PlatformTransactionManager .class );
480
+ defaultTransactionManager = this .beanFactory .getBean (TransactionManager .class );
469
481
this .transactionManagerCache .putIfAbsent (
470
482
DEFAULT_TRANSACTION_MANAGER_KEY , defaultTransactionManager );
471
483
}
@@ -474,11 +486,11 @@ else if (StringUtils.hasText(this.transactionManagerBeanName)) {
474
486
}
475
487
}
476
488
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 );
479
491
if (txManager == null ) {
480
492
txManager = BeanFactoryAnnotationUtils .qualifiedBeanOfType (
481
- beanFactory , PlatformTransactionManager .class , qualifier );
493
+ beanFactory , TransactionManager .class , qualifier );
482
494
this .transactionManagerCache .putIfAbsent (qualifier , txManager );
483
495
}
484
496
return txManager ;
@@ -841,33 +853,30 @@ public ReactiveTransactionSupport(ReactiveAdapter adapter) {
841
853
this .adapter = adapter ;
842
854
}
843
855
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
+
849
859
String joinpointIdentification = methodIdentification (method , targetClass , txAttr );
850
860
851
861
// Optimize for Mono
852
862
if (Mono .class .isAssignableFrom (method .getReturnType ())) {
853
863
return TransactionContextManager .currentContext ().flatMap (context ->
854
- createTransactionIfNecessary (tm , txAttr , joinpointIdentification ).flatMap (it -> {
864
+ createTransactionIfNecessary (rtm , txAttr , joinpointIdentification ).flatMap (it -> {
855
865
try {
856
866
// 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 )
871
880
.onErrorResume (ex ->
872
881
completeTransactionAfterThrowing (it , ex ).then (Mono .error (ex )));
873
882
}
@@ -881,7 +890,7 @@ public Object invokeWithinTransaction(Method method, @Nullable Class<?> targetCl
881
890
882
891
// Any other reactive type, typically a Flux
883
892
return this .adapter .fromPublisher (TransactionContextManager .currentContext ().flatMapMany (context ->
884
- createTransactionIfNecessary (tm , txAttr , joinpointIdentification ).flatMapMany (it -> {
893
+ createTransactionIfNecessary (rtm , txAttr , joinpointIdentification ).flatMapMany (it -> {
885
894
try {
886
895
// Need re-wrapping until we get hold of the exception through usingWhen.
887
896
return Flux
@@ -909,58 +918,8 @@ public Object invokeWithinTransaction(Method method, @Nullable Class<?> targetCl
909
918
.subscriberContext (TransactionContextManager .getOrCreateContextHolder ()));
910
919
}
911
920
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
-
962
921
@ SuppressWarnings ("serial" )
963
- private Mono <ReactiveTransactionInfo > createTransactionIfNecessary (@ Nullable ReactiveTransactionManager tm ,
922
+ private Mono <ReactiveTransactionInfo > createTransactionIfNecessary (ReactiveTransactionManager tm ,
964
923
@ Nullable TransactionAttribute txAttr , final String joinpointIdentification ) {
965
924
966
925
// If no name specified, apply method identification as transaction name.
@@ -972,21 +931,9 @@ public String getName() {
972
931
}
973
932
};
974
933
}
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
- }
989
934
935
+ final TransactionAttribute attrToUse = txAttr ;
936
+ Mono <ReactiveTransaction > tx = (attrToUse != null ? tm .getReactiveTransaction (attrToUse ) : Mono .empty ());
990
937
return tx .map (it -> prepareTransactionInfo (tm , attrToUse , joinpointIdentification , it )).switchIfEmpty (
991
938
Mono .defer (() -> Mono .just (prepareTransactionInfo (tm , attrToUse , joinpointIdentification , null ))));
992
939
}
0 commit comments