1. 导入SperingCahce依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2. 配置文件配置
配置文件选配置我们选择的存储类型(这里选用redis)
spring.cache.type=redis
3. 主启动类
加入注解 @EnableCaching
完成了前面的三步也就可以使用SperingCahce了
4. 配置注入流程
整体流程:CacheAutoConfiguration -> CacheConfigurations -> RedisCacheConfiguration
- 在加入依赖之后会自动的导入CacheAutoConfiguration这个类,CacheAutoConfiguration类会有一个静态方法来导入配置
/**
* {@link ImportSelector} to add {@link CacheType} configuration classes.
*/
static class CacheConfigurationImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
CacheType[] types = CacheType.values();
String[] imports = new String[types.length];
for (int i = 0; i < types.length; i++) {
imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
}
return imports;
}
}
- 具体是由CacheConfigurations这个类来导入配置,这个类中有一个map会导入我们选择的RedisCacheConfiguration
static {
Map<CacheType, Class<?>> mappings = new EnumMap<>(CacheType.class);
mappings.put(CacheType.GENERIC, GenericCacheConfiguration.class);
mappings.put(CacheType.EHCACHE, EhCacheCacheConfiguration.class);
mappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class);
mappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class);
mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class);
mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class);
mappings.put(CacheType.REDIS, RedisCacheConfiguration.class);
mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class);
mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class);
mappings.put(CacheType.NONE, NoOpCacheConfiguration.class);
MAPPINGS = Collections.unmodifiableMap(mappings);
}
- 我们因为我们第2步选择的是redis,因此会导入RedisCacheConfiguration这个配置类,这个配置类会注入一个RedisCacheManager 自己的缓存管理器
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory,
ResourceLoader resourceLoader) {
RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(determineConfiguration(resourceLoader.getClassLoader()));
List<String> cacheNames = this.cacheProperties.getCacheNames();
if (!cacheNames.isEmpty()) {
builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
}
return this.customizerInvoker.customize(builder.build());
}
代码中我们可以看的有一个方法determineConfiguration(),这个方法真是决定我们的RedisCacheConfiguration的方法
- determineConfiguration() 这个方法会判断我们是否自己定义了我们自己的配置类,如果没有的话,那么会采用默认的配置( org.springframework.data.redis.cache.RedisCacheConfiguration
.defaultCacheConfig(); )。源码如下:
private org.springframework.data.redis.cache.RedisCacheConfiguration determineConfiguration(
ClassLoader classLoader) {
if (this.redisCacheConfiguration != null) {
return this.redisCacheConfiguration;
}
Redis redisProperties = this.cacheProperties.getRedis();
org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration
.defaultCacheConfig();
config = config.serializeValuesWith(
SerializationPair.fromSerializer(new JdkSerializationRedisSerializer(classLoader)));
if (redisProperties.getTimeToLive() != null) {
config = config.entryTtl(redisProperties.getTimeToLive());
}
if (redisProperties.getKeyPrefix() != null) {
config = config.prefixKeysWith(redisProperties.getKeyPrefix());
}
if (!redisProperties.isCacheNullValues()) {
config = config.disableCachingNullValues();
}
if (!redisProperties.isUseKeyPrefix()) {
config = config.disableKeyPrefix();
}
return config;
}
- 上一步4中的方法进去可以看到默认的配置(代码中注释的部分)
/**
* Create default {@link RedisCacheConfiguration} given {@link ClassLoader} using the following:
* <dl>
* <dt>key expiration</dt>
* <dd>eternal</dd>
* <dt>cache null values</dt>
* <dd>yes</dd>
* <dt>prefix cache keys</dt>
* <dd>yes</dd>
* <dt>default prefix</dt>
* <dd>[the actual cache name]</dd>
* <dt>key serializer</dt>
* <dd>{@link org.springframework.data.redis.serializer.StringRedisSerializer}</dd>
* <dt>value serializer</dt>
* <dd>{@link org.springframework.data.redis.serializer.JdkSerializationRedisSerializer}</dd>
* <dt>conversion service</dt>
* <dd>{@link DefaultFormattingConversionService} with {@link #registerDefaultConverters(ConverterRegistry) default}
* cache key converters</dd>
* </dl>
*
* @param classLoader the {@link ClassLoader} used for deserialization by the
* {@link org.springframework.data.redis.serializer.JdkSerializationRedisSerializer}.
* @return new {@link RedisCacheConfiguration}.
* @since 2.1
*/
public static RedisCacheConfiguration defaultCacheConfig(@Nullable ClassLoader classLoader) {
看到这里我们可以知道如果我们给ioc导入了redisCacheConfiguration的话,那么就会使用我们的配置,那么我们就可以配置相关的序列化器了
5. 自定义配置
我们使用默认的配置的话,redis中存储的数据是jdk序列化之后的,阅读性非常的差,因此我们模仿源码修改序列化方式为json序列化方式,如下
@Configuration
public class MyCacheConfig {
private final CacheProperties cacheProperties;
public MyCacheConfig(CacheProperties cacheProperties) {
this.cacheProperties = cacheProperties;
}
@Bean
public RedisCacheConfiguration redisCacheConfiguration() {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
CacheProperties.Redis redisProperties = cacheProperties.getRedis();
//将配置文件中所有的配置都生效
if (redisProperties.getTimeToLive() != null) {
config = config.entryTtl(redisProperties.getTimeToLive());
}
if (redisProperties.getKeyPrefix() != null) {
config = config.prefixKeysWith(redisProperties.getKeyPrefix());
}
if (!redisProperties.isCacheNullValues()) {
config = config.disableCachingNullValues();
}
if (!redisProperties.isUseKeyPrefix()) {
config = config.disableKeyPrefix();
}
return config;
}
}
注意,代码中每次添加了一个配置就是会有是个新的对象,我们使用我们原来的config对象接受,最终返回config即可