In the evening, I attended a Honda car club, a Civic of Water. Although I am not a Honda owner, I like cars very much, so I would go to such parties to join in the fun. The red civic of the hatchback is really handsome. All right, let’s cut to the chase.

Spring cache emanager supports a variety of caching components, such as EhCache, jCache, redis, but Redis is the most popular, so we take it as an example. In addition, because of the support for multiple cache databases, the TTL mechanism of each database is different, so the annotations provided by Spring do not have TTL setting parameters, which is very inconvenient in practical application, so today we will increase the TTL configuration of annotations by copying CacheManager.

Spring has implemented caching annotations since 3.1 based on the JSR107 specification, including Cacheable, CachePut, and CacheEvict commonly used annotations.

To start the cache manager, add the @enablecaching annotation to the startup class

@EnableCaching
@SpringBootApplication
public class SpringbootRedisApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringbootRedisApplication.class, args);
	}

}
Copy the code

@Cacheable

This annotation can be applied to a class or method to indicate that all method return objects are added to the cache, or on a method to specify that the method return object is added to the cache.

@CachePut

This annotation is similar to @cacheable except that it is executed every time and replaces the same name in the cache, usually to update the cache.

@CacheEvict

This annotation is used to clear the cacheCacheable (@cacheable) : allEntries default to false to clear the cache specified by key, or true to ignore the key property and cache allEntries. BeforeInvocation when the attribute is true indicates that the clear cache operation is performed before the method.

So with that explained, let’s move on to the real thing, so today we’re just going to expand to @cacheable, and now that we know how to use this, we’re going to use the other two.

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {
    @AliasFor("cacheNames")
    String[] value() default {};

    @AliasFor("value")
    String[] cacheNames() default {};

    String key() default "";

    String keyGenerator() default "";

    String cacheManager() default "";

    String cacheResolver() default "";

    String condition() default "";

    String unless() default "";

    boolean sync() default false;
}
Copy the code

These are the arguments to the @cacheable annotation. The four keys are the Redis key, value, condition, and unless. Value is the cached namespace, condition is a pre-condition, and unless is a post-condition that filters data. Dynamic concatenation can be done using SpEl expressions in the parameters of annotations. Below I provide some test code to demonstrate this.

@service public class implements TestService{Override @cacheable (value = {"test"}, key = "#id") public String test(Integer id) { return "test"; } @override @cacheable (value = {"test1"}, key = "'id-' + #id") public String test1(Integer id) { return "test"; } Override @cacheable (value = {"test2"}, key = "'hash' + #id",condition = "#id > 1") public String test2(Integer id) { return "test"; } @override @cacheable (value = {"test3"}, key = "#id", unless = "#result! = null") public String test3(Integer id) { return null; }}Copy the code

That’s how Cacheable works. It’s pretty convenient, but you can’t set the expiration time of a cache. Let’s implement CacheManager. Next we’ll modify the RedisConfig class from the previous section at !!!!!!

import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; import org.springframework.cache.CacheManager; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.cache.RedisCacheWriter; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; import java.lang.reflect.Method; import java.time.Duration; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); template.setConnectionFactory(redisConnectionFactory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); jackson2JsonRedisSerializer.setObjectMapper(om); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); / / key String serialization method template. SetKeySerializer (stringRedisSerializer); / / the hash key also USES String serialization way template. SetHashKeySerializer (stringRedisSerializer); / / value serialization way by Jackson template. SetValueSerializer (jackson2JsonRedisSerializer); / / the hash value of the serialization way by Jackson template. SetHashValueSerializer (jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { return new RedisCacheManager( RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory), this.getRedisCacheConfigurationWithTtl(30 * 60), , / / the default policy configuration, the key will be to use the enclosing getRedisCacheConfigurationMap ()); / / the specified key strategy } private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() { Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>(); / / SsoCache and BasicDataCache expiration time configuration redisCacheConfigurationMap. Put (" test ", this.getRedisCacheConfigurationWithTtl(24 * 60 * 60)); return redisCacheConfigurationMap; } private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) { Jackson2JsonRedisSerializer<Object> 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); RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig(); redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith( RedisSerializationContext .SerializationPair .fromSerializer(jackson2JsonRedisSerializer) ).entryTtl(Duration.ofSeconds(seconds)); return redisCacheConfiguration; } @Bean public KeyGenerator wiselyKeyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append("." + method.getName()); if (params == null || params.length == 0 || params[0] == null) { return null; } String join = String.join("&", Arrays.stream(params).map(Object::toString).collect(Collectors.toList())); String format = String.format("%s{%s}", sb.toString(), join); return format; }}; }}Copy the code

In the preceding code, we configure the cache time in CacheManager to uniformly handle the expiration time of the cache in the unified namespace. In our use, we only need to configure the value of the annotation in the RedisConfig class, to complete the configuration of the expiration time.

Welcome to pay attention to my public number: Codesls, let’s hi happy skin together.