В Spring CaffeineCacheManager добавлено несколько загрузочных кэшей кофеина
Я хочу добавить несколько различных LoadingCache
к весне CacheManager
Однако я не понимаю, как это возможно, используя CaffeineCacheManager
, Похоже, что для обновления контента возможен только один загрузчик, однако мне нужны отдельные загрузчики для каждого кэша. Можно ли добавить несколько загрузочных кешей в диспетчер кеша Spring? Если так, то как?
CaffeineCacheManager cacheManage = new CaffeineCacheManager();
LoadingCache<String, Optional<Edition>> loadingCache1 =
Caffeine.newBuilder()
.maximumSize(150)
.refreshAfterWrite(5, TimeUnit.MINUTES)
.build(test -> this.testRepo.find(test));
LoadingCache<String, Optional<Edition>> loadingCache2 =
Caffeine.newBuilder()
.maximumSize(150)
.refreshAfterWrite(5, TimeUnit.MINUTES)
.build(test2 -> this.testRepo.find2(test2));
// How do I add to cache manager, and specify a name?
4 ответа
Да, это возможно. Поскольку вам необходимо точно настроить каждый кэш, вы, вероятно, лучше определите их сами. Возвращаясь к вашему примеру, следующим шагом будет:
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(
new CaffeineCache("first", loadingCache1),
new CaffeineCache("second", loadingCache2)));
И тогда вы можете использовать это, как обычно, например,
@Cacheable("first")
public Foo load(String id) { ... }
Если вы используете Spring Boot, вы можете просто выставить отдельный кеш как бины (так org.springframework.cache.Cache
реализации), и мы обнаружим их и создадим SimpleCacheManager
автоматически для вас.
Обратите внимание, что эта стратегия позволяет использовать абстракцию кэша с различными реализациями. first
может быть кофеин тайник и second
кеш от другого провайдера.
Наличие этого класса позволит вам использовать
@Cacheable("cacheA")
где вы хотите как обычно:
@EnableCaching
@Configuration
public class CacheConfiguration {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager();
manager.registerCustomCache("cacheA", defaultCache());
manager.registerCustomCache("cacheB", bigCache());
manager.registerCustomCache("cacheC", longCache());
// to avoid dinamic caches e be sure each name is assigned to a specific config (dynamic = false)
// throws error when tries to use a new cache
manager.setCacheNames(Collections.emptyList());
return manager;
}
private static Cache<Object, Object> defaultCache() {
return Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();
}
private static Cache<Object, Object> bigCache() {
return Caffeine.newBuilder()
.maximumSize(5000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();
}
private static Cache<Object, Object> longCache() {
return Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(1, TimeUnit.HOURS)
.build();
}
}
Спасибо за @rado, это улучшенная версия его ответа. Таким образом, мы можем настроить кеш напрямую из свойств приложения.
cache:
specs:
big-cache:
expire-after: WRITE
timeout: 2h
max-size: 1000
long-cache:
expire-after: ACCESS
timeout: 30d
max-size: 100
Нам нужны свойства кеша для этого
@Data
@EnableConfigurationProperties
@Configuration
@ConfigurationProperties(prefix = "cache")
public class CacheProperties {
private static final int DEFAULT_CACHE_SIZE = 100;
private Map<String, CacheSpec> specs = new HashMap<>();
@Data
public static class CacheSpec {
private Duration timeout;
private Integer maxSize = DEFAULT_CACHE_SIZE;
private ExpireAfter expireAfter = ExpireAfter.WRITE;
}
enum ExpireAfter { WRITE, ACCESS }
}
И тогда мы можем настроить непосредственно из внешнего файла конфигурации
@EnableCaching
@Configuration
@RequiredArgsConstructor
public class CacheConfiguration {
private final CacheProperties cacheProperties;
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager();
Map<String, CacheProperties.CacheSpec> specs = cacheProperties.getSpecs();
specs.keySet().forEach(cacheName -> {
CacheProperties.CacheSpec spec = specs.get(cacheName);
manager.registerCustomCache(cacheName, buildCache(spec));
});
// to avoid dynamic caches and be sure each name is assigned
// throws error when tries to use a new cache
manager.setCacheNames(Collections.emptyList());
return manager;
}
private Cache<Object, Object> buildCache(CacheProperties.CacheSpec cacheSpec) {
if (cacheSpec.getExpireAfter() == CacheProperties.ExpireAfter.ACCESS) {
return Caffeine.newBuilder()
.expireAfterAccess(cacheSpec.getTimeout())
.build();
}
return Caffeine.newBuilder()
.expireAfterWrite(cacheSpec.getTimeout())
.build();
}
}
Теперь вы можете использовать кеш с использованием имени кеша
@Cacheable(cacheNames = "big-cache", key = "{#key}", unless="#result == null")
public Object findByKeyFromBigCache(String key) {
// create the required object and return
}
@Cacheable(cacheNames = "long-cache", key = "{#key}", unless="#result == null")
public Object findByKeyFromLongCache(String key) {
// create the required object and return
}
Обязательно создайте свой собственный Caffeine Cache, используяcom.github.benmanes.caffeine.cache.Ticker
.
Это рабочий пример, протестированный с использованием Java 17, Spring Boot 2.7.7 и Caffeine 3.1.6, где мы настраиваем кэшOne со сроком действия 60 секунд и кэш2, срок действия которого истекает через один час или 3600 секунд:
@Configuration
public class CacheConfig {
@Bean
public CacheManager cacheManagerTicker(Ticker ticker) {
var cacheManager = new SimpleCacheManager();
cacheManager.setCaches(List.of(
this.buildCache("cacheOne", ticker, 1, 60, TimeUnit.SECONDS),
this.buildCache("cacheTwo", ticker, 1, 3600, TimeUnit.SECONDS)
));
return cacheManager;
}
private CaffeineCache buildCache(String cacheName, Ticker ticker,
int maxSize, int expireAfterWrite, TimeUnit timeUnit) {
Caffeine<Object, Object> cacheBuilder = Caffeine.newBuilder();
if (expireAfterWrite > 0) {
cacheBuilder.expireAfterWrite(expireAfterWrite, timeUnit);
}
if (maxSize > 0) {
cacheBuilder.maximumSize(maxSize);
}
cacheBuilder.ticker(ticker);
return new CaffeineCache(cacheName, cacheBuilder.build());
}
@Bean
public Ticker ticker() {
return Ticker.systemTicker();
}
}
Этот пример был адаптирован из раздела «Определение нескольких конфигураций кешей с помощью Spring и Caffeine», где Бен Мейнс указывает, что существует адаптер под названием Coffee Boots, который обеспечивает запрошенное поведение: https://github.com/stepio/coffee-boots