@CacheConfig 作用在类上的配置型注解,cacheNames 设置key前缀, 默认会用::与后面的key拼接,cacheManger 指定缓存使用的cacheManger
@Cacheable 作用在方法上,先获取缓存,缓存没有就执行方法,将方法的返回值缓存起来,eg: @Cacheable(key = “#p0.id”, condition = “#p0.id!=null”) EL表达式参考源码注释
@CachePut 添加缓存:会替换掉现有的缓存 ;eg:@CachePut(key = “#result.id”, unless = “#result==null”)
@CacheEvict 缓存删除, 可以指定删除指定的key,也可以删除全部, 删除缓存的操作默认在方法执行后,通过beforeInvocation设置
配置Redis与caffeine的CacheManager
@Configuration
@RequiredArgsConstructor
@EnableConfigurationProperties({RedisProperties.class, CacheProperties.class})
public class CacheAutoConfig extends CachingConfigurerSupport {
final Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder;
final JacksonProperties jacksonProperties;
final RedisConnectionFactory redisConnectionFactory;
@Bean
public CacheManagerCustomizers cacheManagerCustomizers(ObjectProvider<CacheManagerCustomizer<?>> customizers) {
return new CacheManagerCustomizers(customizers.orderedStream().collect(Collectors.toList()));
}
/**
* this CacheManager use redis cache data ;
*/
@Bean
@Primary
public CacheManager remote(CacheProperties cacheProperties, CacheManagerCustomizers cacheManagerCustomizers,
ObjectProvider<RedisCacheConfiguration> redisCacheConfiguration,
ObjectProvider<RedisCacheManagerBuilderCustomizer> redisCacheManagerBuilderCustomizers) {
RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(
determineConfiguration(cacheProperties, redisCacheConfiguration));
List<String> cacheNames = cacheProperties.getCacheNames();
if (!cacheNames.isEmpty()) {
builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
}
redisCacheManagerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
return cacheManagerCustomizers.customize(builder.build());
}
private org.springframework.data.redis.cache.RedisCacheConfiguration determineConfiguration(
CacheProperties cacheProperties,
ObjectProvider<RedisCacheConfiguration> redisCacheConfiguration) {
return redisCacheConfiguration.getIfAvailable(() -> createConfiguration(cacheProperties));
}
private org.springframework.data.redis.cache.RedisCacheConfiguration createConfiguration(
CacheProperties cacheProperties) {
CacheProperties.Redis redisProperties = cacheProperties.getRedis();
org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration
.defaultCacheConfig();
config = config.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer()))
.computePrefixWith(name -> name + ":");
if (redisProperties.getTimeToLive() != null) {
config = config.entryTtl(redisProperties.getTimeToLive());
}
if (redisProperties.getKeyPrefix() != null) {
config = config.prefixCacheNameWith(redisProperties.getKeyPrefix());
}
if (!redisProperties.isCacheNullValues()) {
config = config.disableCachingNullValues();
}
if (!redisProperties.isUseKeyPrefix()) {
config = config.disableKeyPrefix();
}
return config;
}
/**
* 使用Jackson序列化器
*/
private RedisSerializer<Object> jackson2JsonRedisSerializer() {
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(
Object.class);
jackson2JsonRedisSerializer.setObjectMapper(buildMapper());
return jackson2JsonRedisSerializer;
}
private ObjectMapper buildMapper() {
ObjectMapper objectMapper = jackson2ObjectMapperBuilder.createXmlMapper(false).build();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//设置类型
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL,
JsonTypeInfo.As.PROPERTY);
objectMapper.registerModule(new JavaTimeModule());
//忽略null值
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
return objectMapper;
}
/**
* 配置缓存管理器
*
* @return 缓存管理器
*/
@Bean
public CacheManager local() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(Caffeine.newBuilder().softValues()
// 设置最后一次写入或访问后经过固定时间过期
.expireAfterAccess(30, TimeUnit.SECONDS)
// 初始的缓存空间大小
.initialCapacity(100)
// 缓存的最大条数
.maximumSize(40000));
return cacheManager;
}
@Bean
public CacheLocalRedisResolver doubleCache(@Qualifier("local") CacheManager local, @Qualifier("remote") CacheManager remote) {
return new CacheLocalRedisResolver(local, remote);
}
}
/**
* 本地缓存与redis缓存一起使用
*/
@RequiredArgsConstructor
public class CacheLocalRedisResolver implements CacheResolver {
final CacheManager local;
final CacheManager remote;
@Override
@NonNull
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
Collection<String> cacheNames = context.getOperation().getCacheNames();
Collection<Cache> result = new ArrayList<>(cacheNames.size());
for (String cacheName : cacheNames) {
Cache localCache = local.getCache(cacheName);
Cache remoteCache = remote.getCache(cacheName);
result.add(localCache); // 顺序加入,优先使用本地缓存
result.add(remoteCache);
if (result.size() == 0) {
throw new IllegalArgumentException("Cannot find cache named '" +
cacheName + "' for " + context.getOperation());
}
}
return result;
}
}
决定使用那种缓存时在注解中指定cacheManager =“beanName”
两种缓存组合使用: 指定cacheResolver=“doubleCache”