A Spring Boot 4.1.1 module whose test suite is the evidence for the article: 20 tests producing 22 transcripts under docs/output/, plus 12 documentation chapters. Findings the build pins: - @EnableCaching has no exposeProxy attribute; the widely-copied @EnableCaching(exposeProxy = true) does not compile. - Two methods sharing a cache name and an argument type share a key space, and one silently serves the other's answers. - The documented cache-provider detection order does not match CacheType's enum order in 4.1.1: COUCHBASE before INFINISPAN, and CACHE2K before CAFFEINE. - beforeInvocation = true is NOT deferred by TransactionAwareCacheManagerProxy on 7.0.9 - doEvict picks evictIfPresent, which the decorator does not intercept. - Four of five invalid declarations start a clean context and throw at the first call. - Caffeine on the classpath silently displaces the simple provider.
50 lines
2.7 KiB
Plaintext
50 lines
2.7 KiB
Plaintext
# Why beforeInvocation=true is not deferred by TransactionAwareCacheManagerProxy
|
|
|
|
$ javap -c -p org.springframework.cache.interceptor.AbstractCacheInvoker # spring-context-7.0.9.jar
|
|
protected void doEvict(org.springframework.cache.Cache, java.lang.Object, boolean);
|
|
Code:
|
|
0: iload_3
|
|
1: ifeq 15
|
|
4: aload_1
|
|
5: aload_2
|
|
6: invokeinterface #83, 2 // InterfaceMethod org/springframework/cache/Cache.evictIfPresent:(Ljava/lang/Object;)Z
|
|
11: pop
|
|
12: goto 22
|
|
15: aload_1
|
|
16: aload_2
|
|
17: invokeinterface #87, 2 // InterfaceMethod org/springframework/cache/Cache.evict:(Ljava/lang/Object;)V
|
|
22: goto 40
|
|
25: astore 4
|
|
|
|
$ javap -c -p org.springframework.cache.transaction.TransactionAwareCacheDecorator # spring-context-support-7.0.9.jar
|
|
public void evict(java.lang.Object);
|
|
Code:
|
|
0: invokestatic #48 // Method org/springframework/transaction/support/TransactionSynchronizationManager.isSynchronizationActive:()Z
|
|
3: ifeq 21
|
|
6: new #71 // class org/springframework/cache/transaction/TransactionAwareCacheDecorator$2
|
|
9: dup
|
|
10: aload_0
|
|
11: aload_1
|
|
12: invokespecial #73 // Method org/springframework/cache/transaction/TransactionAwareCacheDecorator$2."<init>":(Lorg/springframework/cache/transaction/TransactionAwareCacheDecorator;Ljava/lang/Object;)V
|
|
15: invokestatic #59 // Method org/springframework/transaction/support/TransactionSynchronizationManager.registerSynchronization:(Lorg/springframework/transaction/support/TransactionSynchronization;)V
|
|
18: goto 31
|
|
21: aload_0
|
|
22: getfield #15 // Field targetCache:Lorg/springframework/cache/Cache;
|
|
25: aload_1
|
|
public boolean evictIfPresent(java.lang.Object);
|
|
Code:
|
|
0: aload_0
|
|
1: getfield #15 // Field targetCache:Lorg/springframework/cache/Cache;
|
|
4: aload_1
|
|
5: invokeinterface #80, 2 // InterfaceMethod org/springframework/cache/Cache.evictIfPresent:(Ljava/lang/Object;)Z
|
|
10: ireturn
|
|
|
|
|
|
doEvict(cache, key, true) -> Cache.evictIfPresent -> straight to the target cache
|
|
doEvict(cache, key, false) -> Cache.evict -> registerSynchronization, runs after commit
|
|
|
|
spring-framework#23192 reported beforeInvocation=true being swallowed by the
|
|
transaction-aware decorator. On 7.0.9 it is not: the immediate path uses a method
|
|
the decorator does not intercept. Note also that the decorator ships in
|
|
spring-context-support, not spring-context.
|