第九更,spring cache设置指定key缓存过期时间,基于spring的生命周期,在创建CacheManager之前获取所有的cacheName,并根据分割符“#”切分cacheName,得到过期时间,并设置,不包含分割符的cacheName,使用默认过期时间(2天)。
Maven依赖
<dependencies>
<!--使用的是2.1.5.RELEASE版本-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
</dependencies>
Cache配置类
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.CacheOperation;
import org.springframework.cache.interceptor.CacheOperationSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.*;
import java.time.Duration;
import java.util.*;
@EnableCaching
@Configuration
public class CacheConfig implements ApplicationContextAware {
private Set<String> cacheNames = new HashSet<>();
private static final String SEPARATOR = "#";
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
//默认过期时间2天
RedisCacheConfiguration defaultConfiguration = getRedisCacheConfigurationWithTtl(2 * 24 * 3600);
RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager
.builder(connectionFactory)
.cacheDefaults(defaultConfiguration);
if (!CollectionUtils.isEmpty(cacheNames)) {
Map<String, RedisCacheConfiguration> cacheConfigurations = new LinkedHashMap<>();
for (String cacheName : cacheNames) {
if (cacheName.contains(SEPARATOR)) {
String[] strs = StringUtils.split(cacheName, SEPARATOR);
Assert.notNull(strs);
long ttl = Long.parseLong(strs[1].trim());
RedisCacheConfiguration customizedConfiguration = getRedisCacheConfigurationWithTtl(ttl);
cacheConfigurations.put(cacheName, customizedConfiguration);
}
}
if (cacheConfigurations.size() > 0) {
builder.withInitialCacheConfigurations(cacheConfigurations);
}
}
return builder.build();
}
private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(long ttl) {
return RedisCacheConfiguration
.defaultCacheConfig()
.disableCachingNullValues()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
.entryTtl(Duration.ofSeconds(ttl));
}
//实现ApplicationContextAware接口的Bean会被提前实例化,这个方法会优先执行
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (!(applicationContext instanceof ConfigurableApplicationContext)) {
return;
}
ConfigurableApplicationContext context = (ConfigurableApplicationContext) applicationContext;
//CacheOperationSource 可以被提前实例化,是spring cache提供的工具类
CacheOperationSource cacheOperationSource = context.getBean(CacheOperationSource.class);
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) beanFactory.getBeanDefinition(beanName);
try {
Class<?> beanClass = beanDefinition.resolveBeanClass(ClassUtils.getDefaultClassLoader());
if (beanClass != null) {
ReflectionUtils.doWithMethods(beanClass, m -> {
Collection<CacheOperation> cacheOperations = cacheOperationSource.getCacheOperations(m, beanClass);
if (!CollectionUtils.isEmpty(cacheOperations)) {
for (CacheOperation operation : cacheOperations) {
cacheNames.addAll(operation.getCacheNames());
}
}
}
);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}