- SpringBoot:3.0.1 + Java17 + starter-cache + starter-data-redis
- 简单的 jpa 查询数据,缓存到 redis 中
@EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true) @EnableCaching public class StartupApplication { } @Service public class AccountService { @Cacheable(cacheNames = "accountsActivated", sync = true) public List<AccountDto> retrieveActivatedCacheable() { } public AccountDto retrieveActivatedByName(String name) { // 这里 call retrieveActivatedCacheable() 不会从缓存中查询 } - 原因是 spring aop 实现原理是动态代理,同一个类中调用切点方法,advise 失效
- aopContext.getCurrentProxy
- ((AccountService) AopContext.currentProxy()).retrieveActivatedCacheable()
- java.lang.IllegalStateException: Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available, and ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context.
- exposeProxy = true not in effect Issue #16516 spring-projects/spring-boot 跟这个 issue 基本一样,没有解决方案
- ((AccountService) AopContext.currentProxy()).retrieveActivatedCacheable()
- 两个方法放不同类
- 最终方案,业务关联性强,放不同类没意义
- self-inject 和 Compile-time weaver Invoke Spring @Cacheable from Another Method of Same Bean | Baeldung
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) public class AccountService @Autowired private AccountService self; @Cacheable(cacheNames = "accountsActivated", sync = true) public List<AccountDto> retrieveActivatedCacheable() { } public AccountDto retrieveActivatedByName(String name) { self.retrieveActivatedCacheable()..... - 报错完全搞不懂发生了什么,貌似和 java9 的 modules 有关,
java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class demo.usul.dto.AccountDto (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; demo.usul.dto.AccountDto is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @5d339696)
- 但是我已经设置了 vm options, 或者 spring.devtools.restart.enabled=false 都没用
--add-opens=java.base/java.time=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED - 关键 self-inject ,或者想办法在自己内部拿到自己 bean 的方法都有点奇怪
- compile-time weaver 更不推荐,要引入 aspectj 的 weaver 来编译,好像在编译过程多了一个 weaver compiler 的过程,尝试用 aspectj-maven-plugin ,但是搞不定,貌似跟 jdk17 不兼容
- load-time weaver 使用 spring 提供的 LTW, 不需要引入 aspectj 的 weaver ,貌似是最推荐的方案, spring 原生 LTW
- 还是失败, startupApplication 上添加注解 @EnableCaching(mode = AdviceMode.ASPECTJ)和 @EnableLoadTimeWeaving
- 其余不变,vm 参数加上 -javaagent:/path/to/spring-instrument-6.0.13.jar
- 没用
- 如果换成 -javaagent:/path/to/aspectjweaver-1.9.19.jar
- 起不来,看不懂的报错
