Spring Data Redis encapsulates various operations on the Redis client for us, simplifying the use.

  • When Redis operates as a database or message queue, we typically use RedisTemplate to operate
  • When Redis is used as a Cache, we can use it as an implementation of Spring Cache, directly through annotations

About the use of RedisTemplate reference: blog.didispace.com/springbootr…

The following summary uses Redis as the cache

Introduction of depend on

Since version 1.4, the spring-boot-starter-redis dependency has been renamed.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>1.5.2. RELEASE</version>
</dependency>
Copy the code

The configuration file

spring:
  redis:
    host: 127.0. 01.
    port: 6379
    timeout: 0
    database: 0
    pool:
      max-active: 8
      max-wait: - 1
      max-idle: 8
      min-idle: 0
Copy the code

SpringBoot will then automatically configure Redis, inject the relevant beans, and we can use @Cacheconfig, @Cacheable, @CachePut, @cacheevict.

Problems with Cache annotations

In the cache object collection, the cache is stored as a key-value. When no cached key is specified, SpringBoot uses SimpleKeyGenerator to generate the key.

public class SimpleKeyGenerator implements KeyGenerator {

	@Override
	public Object generate(Object target, Method method, Object... params) {
		return generateKey(params);
	}

	/** * Generate a key based on the specified parameters. */
	public static Object generateKey(Object... params) {
		if (params.length == 0) {
			return SimpleKey.EMPTY;
		}
		if (params.length == 1) {
			Object param = params[0];
			if(param ! =null && !param.getClass().isArray()) {
				returnparam; }}return newSimpleKey(params); }}Copy the code
	public SimpleKey(Object... elements) {
		Assert.notNull(elements, "Elements must not be null");
		this.params = new Object[elements.length];
		System.arraycopy(elements, 0.this.params, 0, elements.length);
		this.hashCode = Arrays.deepHashCode(this.params);
	}
Copy the code

Looking at the source code, you can see that it is a key generated using a combination of method parameters. There is a problem: if two methods have the same parameters but different execution logic, the second method will hit the cache of the first method. The workaround is to specify the key in the @cacheable annotation parameter, or to implement a KeyGenerator of your own and specify the KeyGenerator in the annotation. However, if there are many such cases, specifying key and KeyGenerator for each one can be troublesome.

Spring also provides a solution: Inherit CachingConfigurerSupport and rewrite keyGenerator()

Post the code below:

@EnableCaching
@Configuration
public class RedisCacheConfig extends CachingConfigurerSupport {

    @Autowired
    private JedisConnectionFactory jedisConnectionFactory;

    @Bean
    public RedisTemplate redisTemplate(a) {
        StringRedisTemplate redisTemplate = new StringRedisTemplate(jedisConnectionFactory);

        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Bean
    public CacheManager cacheManager(a) {
        String[] cacheNames = {"app_default"."users"."blogs"."goods"."configs"."info"};
        RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate(), Arrays.asList(cacheNames));
        redisCacheManager.setDefaultExpiration(86400);
        return redisCacheManager;
    }

    @Bean
    public Cache cache(a) {
        return cacheManager().getCache("app_default");
    }

    @Bean
    @Override
    public KeyGenerator keyGenerator(a) {
        return (target, method, objects) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName());
            sb.append("... "" + method.getName() + ":");
            for (Object obj : objects) {
                sb.append(obj.toString());
            }
            returnsb.toString(); }; }}Copy the code

In this case, the cache key is the package name + method name + parameter list, which makes it hard to conflict.