起因
项目中希望在springboot中配置使用缓存,在这里将网上的综合配置记录一下。
基于spring中注解方式@Cacheable
1.pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.添加@EnableCaching
@Slf4j
@SpringBootApplication
@MapperScan("com.my.equipment.web")
@EnableCaching
@EnableTransactionManagement
public class Application {
public static void main(String[] args) {
ApplicationContext context= SpringApplication.run(Application.class,args);
String serverPort=context.getEnvironment().getProperty("server.port");
log.info("start at http://localhost:"+serverPort);
}
}
补充
关于@Cacheable 的具体参数可以参考SpringBoot 缓存之 @Cacheable 详细介绍 - InfoQ 写作平台
-
@CachePut更新 Redis 中对应键的值。属性和
@Cacheable相同
注意:
cacheNames和key要跟@Cacheable()里的一致,才会正确更新。@CachePut()和@Cacheable()注解的方法返回值要一致
-
@CacheEvict删除 Redis 中对应键的值。 在需要删除缓存的方法上加注解:
@CacheEvict(cacheNames = "prodcut", key = "123"),执行完这个方法之后会将 Redis 中对应的记录删除。
此外:cacheNames 也可以统一写在类上面, @CacheConfig(cacheNames = "product") ,具体的方法上就不用写。
@Service
@CacheConfig(cacheNames = "simSlave")
public class SimSlaveServiceImpl implements SimSlaveService {
@Transactional
@Cacheable(key = "#id")
public SlaveSimData getSlaveData(int id) {
SlaveSimData slaveSimData = slaveSimDataMapper.selectByPrimaryKey(id);
System.out.println("生成数据缓存"+id);
return slaveSimData;
}
}
存在问题:无法设置有过期时间的
解决方法:自定义redisManager
package com.my.equipment.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class CacheConfig {
@Autowired
ResourceLoader resourceLoader;
private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {
//设置 json 序列化
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
jackson2JsonRedisSerializer.setObjectMapper(om);
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).
// 设置过期时间 entryTtl()参数当小于等于0时,将缓存时间设置为永久
entryTtl(Duration.ofSeconds(seconds));
return redisCacheConfiguration;
}
private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() {
Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>();
redisCacheConfigurationMap.put("simSlave", this.getRedisCacheConfigurationWithTtl(60 * 60 ));
return redisCacheConfigurationMap;
}
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
//使用默认的redisManager管理器
return new RedisCacheManager(
RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),
this.getRedisCacheConfigurationWithTtl(-1),
this.getRedisCacheConfigurationMap()
);
}
}
@Service
@CacheConfig(cacheNames = "simSlave")
public class SimSlaveServiceImpl implements SimSlaveService {
@Override
@Transactional
@Cacheable(key = "#id")
public SlaveSimData getSlaveData(int id) {
SlaveSimData slaveSimData = slaveSimDataMapper.selectByPrimaryKey(id);
System.out.println("生成数据缓存"+id);
return slaveSimData;
}
}
优化
上面的配置方法,如果希望设置时间需要基于 redisCacheConfigurationMap.put,将key与过期时间分离,在这里引用SpringBoot缓存注解@Cacheable之自定义key策略及缓存失效时间指定 - 掘金 (juejin.cn)
自定义的策略如下:
- value中,等号左边的为cacheName, 等号右边的为失效时间
要实现这个逻辑,可以扩展一个自定义的RedisCacheManager,如
package com.my.equipment.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.time.Duration;
import java.util.Map;
public class TtlRedisCacheManager extends RedisCacheManager {
public TtlRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
super(cacheWriter, defaultCacheConfiguration);
}
public TtlRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration, String... initialCacheNames) {
super(cacheWriter, defaultCacheConfiguration, initialCacheNames);
}
public TtlRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration, boolean allowInFlightCacheCreation, String... initialCacheNames) {
super(cacheWriter, defaultCacheConfiguration, allowInFlightCacheCreation, initialCacheNames);
}
public TtlRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration, Map<String, RedisCacheConfiguration> initialCacheConfigurations) {
super(cacheWriter, defaultCacheConfiguration, initialCacheConfigurations);
}
public TtlRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration, Map<String, RedisCacheConfiguration> initialCacheConfigurations, boolean allowInFlightCacheCreation) {
super(cacheWriter, defaultCacheConfiguration, initialCacheConfigurations, allowInFlightCacheCreation);
}
@Override
protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
String[] cells = StringUtils.delimitedListToStringArray(name, "=");
name = cells[0];
if (cells.length > 1) {
long ttl = Long.parseLong(cells[1]);
// 根据传参设置缓存失效时间
cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl));
}
return super.createRedisCache(name, cacheConfig);
}
}
public class CacheConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
return new TtlRedisCacheManager(
RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),
this.getRedisCacheConfigurationWithTtl(-1)
);
}
}
@Service
@CacheConfig(cacheNames = "simSlave=3600")
public class SimSlaveServiceImpl implements SimSlaveService {
@Override
@Transactional
@Cacheable(key = "#id")
public SlaveSimData getSlaveData(int id) {
SlaveSimData slaveSimData = slaveSimDataMapper.selectByPrimaryKey(id);
System.out.println("生成数据缓存"+id);
return slaveSimData;
}
}
注意@CacheConfig(cacheNames = "simSlave=3600")与 redisCacheConfigurationMap.put("simSlave", this.getRedisCacheConfigurationWithTtl(60 * 60 ));同时使用@CacheConfig(cacheNames = "simSlave=3600")的优先级更高。