spring - Spring - 如何使用 aspectJ 缓存自调用?
问题描述
谢谢你点击我的问题。我想在自调用中调用缓存方法,所以需要使用AspectJ。(缓存的配置没问题)
- 添加 AspectJ 依赖项
implementation 'org.springframework.boot:spring-boot-starter-aop'
- 将 @EnableCaching(mode = AdviceMode.ASPECTJ) 添加到我的 application.java
@EnableJpaAuditing
@EnableCaching(mode = AdviceMode.ASPECTJ) // <-- here
@SpringBootApplication
public class DoctorAnswerApplication {
public static void main(String[] args) {
SpringApplication.run(DoctorAnswerApplication.class, args);
}
}
- 我的服务.java
@Service
public class PredictionService {
@Cacheable(value = "findCompletedRecordCache")
public HealthCheckupRecord getRecordComplete(Long memberId, String checkupDate) {
Optional<HealthCheckupRecord> recordCheckupData;
recordCheckupData = healthCheckupRecordRepository.findByMemberIdAndCheckupDateAndStep(memberId, checkupDate, RecordStep.COMPLETE);
return recordCheckupData.orElseThrow(NoSuchElementException::new);
}
}
- 我的测试代码
@Test
public void getRecordCompleteCacheCreate() {
// given
Long memberId = (long)this.testUserId;
List<HealthCheckupRecord> recordDesc = healthCheckupRecordRepository.findByMemberIdAndStepOrderByCheckupDateDesc(testUserId, RecordStep.COMPLETE);
String checkupDate = recordDesc.get(0).getCheckupDate();
String checkupDate2 = recordDesc.get(1).getCheckupDate();
// when
HealthCheckupRecord first = predictionService.getRecordComplete(memberId,checkupDate);
HealthCheckupRecord second = predictionService.getRecordComplete(memberId,checkupDate);
HealthCheckupRecord third = predictionService.getRecordComplete(memberId,checkupDate2);
// then
assertThat(first).isEqualTo(second);
assertThat(first).isNotEqualTo(third);
}
我没有什么……?我没有开设任何与 aspectJ 相关的课程。我认为@EnableCaching(mode = AdviceMode.ASPECTJ)
通过 AspectJ 而不是 Spring AOP(proxy) 使 @Cacheable 工作。
解决方案
感谢@kriegaex,他通过指出 spring-aspects 依赖和 load-time-weaving javaagent 要求来修复我。为了方便其他人,Spring Boot 和 Maven 的配置片段如下。
(注意:最后,我觉得这一切(以及副作用)对于我的项目来说并不值得。请参阅我的另一个答案,了解一个简单但有点难看的解决方法。)
聚甲醛:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
应用配置:
@Configuration
@EnableCaching(mode = AdviceMode.ASPECTJ)
public class ApplicationConfig { ... }
目标方法:
@Cacheable(cacheNames = { "cache-name" })
public Thingy fetchThingy(String identifier) { ... }
编织机制:
选项 1:加载时间编织(Spring 默认)
使用 JVM javaagent 参数或添加到您的 servlet 容器库
-javaagent:<path-to-jar>/aspectjweaver-<version>.jar
选项 2:编译时编织
(这应该是可行的,但我发现缺少与 Spring Caching 一起使用的连贯示例 - 请参阅下面的进一步阅读)
使用aspectj-maven-plugin:https ://www.mojohaus.org/aspectj-maven-plugin/index.html
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.11</version>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<outxml>true</outxml>
<showWeaveInfo>false</showWeaveInfo>
<Xlint>warning</Xlint>
<verbose>false</verbose>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<complianceLevel>${java.version}</complianceLevel>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
出于参考/搜索的目的,这里是开始这一切的错误:
Caused by: java.io.FileNotFoundException: class path resource [org/springframework/cache/aspectj/AspectJCachingConfiguration.class] cannot be opened because it does not exist
更多阅读:
- AOP 和 Spring:https ://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop
- AspectJ 教程(Baeldung):https ://www.baeldung.com/aspectj
- Complie-Time Weaving vs Load-Time Weaving:https ://stackoverflow.com/a/23042793/631272
- 春季简报中的 CTW 与 LTW:https ://stackoverflow.com/a/41370471/631272
- CTW 与 LTW 教程:https ://satenblog.wordpress.com/2017/09/22/spring-aspectj-compile-time-weaving/
- 让 CTW 在 Eclipse M2e 中工作:https ://stackoverflow.com/a/19616845/631272
- CTW 和 Java 11 问题(可能是我与之斗争的一部分):https ://www.geekyhacker.com/2020/03/28/how-to-configure-aspectj-in-spring-boot/
推荐阅读
- reactjs - 使用键盘输入事件时意外使用“事件”无限制全局变量
- reactjs - [React Hooks] 无法在 onClick 箭头函数中使用参数获取更改状态
- cairo - 如何使用 stbi_load 输出格式为 STBI_grey 并使用与 cairo 相同的步幅?
- ruby-on-rails - 当我下载 Excel 文件时,会存储奇怪的文件
- amazon-web-services - 域转发为 AWS 和 GoDaddy 提供 403 错误
- flutter - Flutter 加载 Widget 类颜色
- python - 合并两张表,一张只带有标题,另一张带有 bs4 的表值
- docusignapi - 用于 DocuSign 集成的 JWT 或 AWT
- firebase - 在firebase中复制树结构的最佳方法?
- node.js - Nodejs API 使用 Promise 等待 websocket 事件