前面介绍了CacheAutoConfiguration默认生效的是SimpleCacheConfiguration配置类,实际中我们更多的是利用redis作为缓存,现在我们继续看看RedisCacheConfiguration有什么不同
原理分析
- 在引入redis相关依赖之后,对应的RedisCacheConfiguration配置类就生效了。因为RedisCacheConfiguration的加载顺序在SimpleCacheConfiguration前面,所以RedisCacheConfiguration配置会先生效
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisConnectionFactory.class)
@AutoConfigureAfter(RedisAutoConfiguration.class)
@ConditionalOnBean(RedisConnectionFactory.class)
@ConditionalOnMissingBean(CacheManager.class)
@Conditional(CacheCondition.class)
class RedisCacheConfiguration {
}
- 在RedisCacheConfiguration配置类中,帮我们向容器注入了一个RedisCacheManager的redis类型的缓存管理器
class RedisCacheConfiguration {
// 向容器注入RedisCacheManager缓存管理器,通过缓存管理器管理RedisCache缓存组件
@Bean
RedisCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers cacheManagerCustomizers,
ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration,
ObjectProvider<RedisCacheManagerBuilderCustomizer> redisCacheManagerBuilderCustomizers,
RedisConnectionFactory redisConnectionFactory, ResourceLoader resourceLoader) {
RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(
determineConfiguration(cacheProperties, redisCacheConfiguration, resourceLoader.getClassLoader()));
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());
}
}
- 在RedisCacheManager中会加载初始化缓存组件,如果存在会循环创建RedisCache组件
public class RedisCacheManager extends AbstractTransactionSupportingCacheManager {
/**
* 加载缓存组件
*/
@Override
protected Collection<RedisCache> loadCaches() {
List<RedisCache> caches = new LinkedList<>();
for (Map.Entry<String, RedisCacheConfiguration> entry : initialCacheConfiguration.entrySet()) {
caches.add(createRedisCache(entry.getKey(), entry.getValue()));
}
return caches;
}
/**
* 创建RedisCache缓存组件
*/
protected RedisCache createRedisCache(String name, @Nullable RedisCacheConfiguration cacheConfig) {
return new RedisCache(name, cacheWriter, cacheConfig != null ? cacheConfig : defaultCacheConfig);
}
}
- 在RedisCacheManager缓存管理器中来对redis缓存组件(RedisCache)进行操作
public class RedisCache extends AbstractValueAdaptingCache {
/**
* 查找缓存
* @param key
* @return
*/
@Override
protected Object lookup(Object key) {
// createAndConvertCacheKey会进行序列化key,如果有使用前缀,也是在这里面拼接的 cacheConfig.getKeyPrefixFor(name) + key;
byte[] value = cacheWriter.get(name, createAndConvertCacheKey(key));
if (value == null) {
return null;
}
// 序列化value
return deserializeCacheValue(value);
}
/**
* 更新缓存
* @param key
* @param value
*/
@Override
public void put(Object key, @Nullable Object value) {
Object cacheValue = preProcessCacheValue(value);
if (!isAllowNullValues() && cacheValue == null) {
throw new IllegalArgumentException(String.format(
"Cache '%s' does not allow 'null' values. Avoid storing null via '@Cacheable(unless=\"#result == null\")' or configure RedisCache to allow 'null' via RedisCacheConfiguration.",
name));
}
cacheWriter.put(name, createAndConvertCacheKey(key), serializeCacheValue(cacheValue), cacheConfig.getTtl());
}
/**
* 按key清除某个缓存
* @param key
*/
@Override
public void evict(Object key) {
cacheWriter.remove(name, createAndConvertCacheKey(key));
}
}
需要注意的点
-
存储对象需要序列化
-
默认使用jdk的序列化规则,如需使用json需自定义配置类
@Configuration
public class MyRedisConfig {
@Bean
RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
Jackson2JsonRedisSerializer<Student> serializer = new Jackson2JsonRedisSerializer<>(Student.class);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(objectMapper);
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofDays(1))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer))
.disableCachingNullValues();
return RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(config).build();
}
}
gitee代码示例