CacheManager configuration of SpringBoot2.0

The cache config of spring boot 2.0 has changed a lot, and the build mode is generally used. 

 

A relatively simple configuration:

 

@Bean(name = "cacheManager")
@Primary
public CacheManager cacheManager(ObjectMapper objectMapper, RedisConnectionFactory redisConnectionFactory) {
    RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofSeconds(CacheTime.DEFAULT))
            .disableCachingNullValues()
            .computePrefixWith(cacheName -> "yourAppName".concat(":").concat(cacheName).concat(":"))
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(createJackson2JsonRedisSerializer(objectMapper)));
 
    return RedisCacheManager.builder(redisConnectionFactory)
            .cacheDefaults(cacheConfiguration)
            .build();
}

 Code Description:

 

1. entryTtl: defines the default cache time-to-live.

2. disableCachingNullValues: Disable caching of Null objects. This depends on the requirements.

3. computePrefixWith: The cache key prefix is ​​defined here to avoid key name conflicts between different projects of the company.

4. serializeKeysWith, serializeValuesWith: Define the serialization protocol of key and value, and the hash key and hash value are also defined.

 

 

Custom Cache key generation strategy

In the above configuration, the generated key is the default SimpleKey object, which is really not easy to use, and it is easy to cause the problem that the redis key is too long. Here, we customize the key generation strategy and convert the method parameters into hashcode, as redis key. Two things need to be done, one is to add a custom ConversionService, and the other is to customize a KeyGenerator.

 

@Bean(name = "cacheManager")
@Primary
public CacheManager cacheManager(ObjectMapper objectMapper, RedisConnectionFactory redisConnectionFactory) {
    RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofSeconds(CacheTime.DEFAULT))
            .disableCachingNullValues()
            .computePrefixWith(cacheName -> "yourAppName".concat(":").concat(cacheName).concat(":"))
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(createJackson2JsonRedisSerializer(objectMapper)))
            .withConversionService(new CacheKeyConversionService());
 
    return RedisCacheManager.builder(redisConnectionFactory)
            .cacheDefaults(cacheConfiguration)
            .build();
}

@Bean(name = "cacheKeyGenerator")
@Primary
 public KeyGenerator keyGenerator() {
     return (target, method, params) -> CacheHashCode.of(params);
 }

 Note that the sentence withConversionService(new CacheKeyConversionService()) registers a ConversionService, which acts on the Cache object. The KeyGenerator will use the method annotated with @Cacheable to convert the parameters of the method to hashCode. In this case, the Cache object and @Cacheable are connected , can achieve interoperability. That is, the cache data of the @Cacheable method can be read by directly manipulating the Cache object. This is very useful in practical projects. But the cost of doing so is that the cache is easily abused by developers, and architects I have to consider this. I joined it at the strong request of the developers, and I plan to disable the communication between Cache and @Cacheable by default through a configuration. 

 

Add other code:

 

/**
 * Convert  cache key to hash code.
 */
class CacheKeyConversionService implements ConversionService {
    @Override
    public boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType) {
        return true;
    }
 
    @Override
    public boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
        return true;
    }
 
    @Nullable
    @Override
    public <T> T convert(@Nullable Object source, Class<T> targetType) {
        return (T) convert(source);
    }
 
    @Nullable
    @Override
    public Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
        return convert(source);
    }
 
    private Object convert(Object source) {
        if (source instanceof CacheHashCode) {
            return ((CacheHashCode) source).hashString();
        }
        return CacheHashCode.of(source).hashString();
    }
}
 
/**
 * Hash code generator.
 */
static class CacheHashCode {
    private Object[] params;
    private int code;
 
    private CacheHashCode(Object[] params) {
        this.params = params;
        this.code = Arrays.deepHashCode(params);
    }
 
    public static CacheHashCode of(Object object) {
        return new CacheHashCode(ArrayUtil.isArray(object) ? ArrayUtil.toObjectArray(object) : new Object[]{object});
    }
 
    @Override
    public int hashCode() {
        return code;
    }
 
    public String hashString() {
        return code + "";
    }
 
    @Override
    public String toString() {
        return "CacheHashCode{" +
                "params=" + Arrays.toString(params) +
                ", code=" + code +
                '}';
    }
}

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326116395&siteId=291194637
Recommended