SpringCache使用和自定义配置流程原理

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

  1. 在加入依赖之后会自动的导入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;
		}

	}
  1. 具体是由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);
	}
  1. 我们因为我们第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的方法

  1. 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;
	}
  1. 上一步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即可

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值