java - Spring 的 Cacheable Annotation 如何为通过 new 关键字初始化的类工作。(在类构造函数中,通过 Bean 初始化)
问题描述
CacheableService
在我们的服务中,我们正在初始化一个 bean(比如“A”),并使用 -在内部构造一个Object new CacheableService()
。据我所知@Cacheable
,如果使用“new”关键字初始化类,spring 的注释将不适用于类方法。
那么缓存方法响应的替代方法或方法是什么?
设想 :
<bean class="com.package.src.A"/>
public class A {
Map<String, CacheableService> map;
public CacheableService2() {
map = new HashedMap();
map.put("a", new CacheableService());
}
}
import org.springframework.cache.annotation.Cacheable;
public class CacheableService {
@Cacheable(value = "entityCount", key = "#criteria.toString()")
public int someEntityCount(final String criteria) {
System.out.println("Inside function : " + criteria);
return 5;
}
}
解决方案
这是一个演示使用 Spring Boot 进行缓存的最小示例。可以在此处找到以下示例的代码。
转到https://start.spring.io/并创建一个新的 Spring Boot 项目。确保包含“Spring 缓存抽象”,这会导致将此条目添加到您的 pom 中:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
将 @EnableCaching 注解添加到您的应用程序:
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@EnableCaching
@SpringBootApplication
public class CacheableApplication {
public static void main(String[] args) {
SpringApplication.run(CacheableApplication.class, args);
}
}
您的服务:
package com.example;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class CacheableService {
@Cacheable(value = "entityCount")
public int someEntityCount(final String criteria) {
System.out.print(String.format("Inside function: %s", criteria));
return 5;
}
}
A类:
package com.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class A {
private CacheableService cacheableService;
public A(@Autowired CacheableService cacheableService) {
this.cacheableService = cacheableService;
}
public int getEntityCount(String criteria) {
return cacheableService.someEntityCount(criteria);
}
}
然后这是一个测试,证明缓存正在工作。正如您在测试中看到的那样,a.getEntityCount("foo") 被调用了两次,但在标准输出中我们只看到“Inside function: foo”被打印了一次。因此,我们验证了第二次调用导致缓存被用于产生结果。
package com.example;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import static org.junit.jupiter.api.Assertions.assertEquals;
@SpringBootTest
class CacheableTest {
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
@Autowired
private A a;
@BeforeEach
public void init() {
System.setOut(new PrintStream(outContent));
}
@Test
public void testCaching() {
a.getEntityCount("foo");
a.getEntityCount("foo");
assertEquals("Inside function: foo", outContent.toString());
}
}
编辑:如果您想将缓存移到 Spring 生命周期之外并手动管理它,那么我建议使用Caffeine。这是相同的示例,但现在不涉及任何 Spring。
您的服务:
package com.example.withoutspring;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import java.util.concurrent.TimeUnit;
public class CaffeineCachingService {
private LoadingCache<String, Integer> entityCountCache = Caffeine.newBuilder()
.expireAfterAccess(5, TimeUnit.MINUTES)
.build(key -> someEntityCount(key));
public int cachedEntityCount(final String criteria) {
return entityCountCache.get(criteria);
}
private int someEntityCount(final String criteria) {
System.out.print(String.format("Inside function: %s", criteria));
return 5;
}
}
B类:
package com.example.withoutspring;
public class B {
private CaffeineCachingService cacheableService;
public B() {
cacheableService = new CaffeineCachingService();
}
public int getEntityCount(String criteria) {
return cacheableService.cachedEntityCount(criteria);
}
}
同样的测试,但没有 Spring:
package com.example.withoutspring;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CaffeineCacheableTest {
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private B b = new B();
@BeforeEach
public void init() {
System.setOut(new PrintStream(outContent));
}
@Test
public void testCaching() {
b.getEntityCount("foo");
b.getEntityCount("foo");
assertEquals("Inside function: foo", outContent.toString());
}
}
显然,您需要调整缓存以执行您想要的方式,因此可能在 5 分钟后驱逐缓存的值不是您想要的,但是如果您访问 Caffeine Github 页面,您将看到很多详细的示例如何配置缓存以满足你的用例。
希望这可以帮助!
推荐阅读
- django - 在 Django 数据模型中存储 HTML
- lucene - 什么是相当于 SQL `IS NULL OR someDate > GETDATE()` 的 Lucene 查询?
- r - 在R RStudio中选择一列的两个特定值
- javascript - 为什么单击按钮时值不会增加或减少
- sql - SQL查询将每个值的列格式更改为行
- javascript - 当机器人响应并且用户想要继续时,如何让机器人回答用户,就像对话一样(但不重复)
- javascript - 如何在 Electron 应用程序中激活 Ctrl+F 研究快捷键?
- c++ - 如何获取 std::set 指针中的第一个元素,其中指针指向特定值?
- web-scraping - 下载复杂的 3D JS/Canvas 网页以供离线使用
- python - python从包含特定表达式的字符串中删除特定行