1. SpringCache fails in practice

1.1. The pom

  1. There are mainly the following two
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <! <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>Copy the code

1.2. Redis configuration

package com.zhiyis.common.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import redis.clients.jedis.JedisPoolConfig; import java.lang.reflect.Method; @Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport { private static Logger logger =  LoggerFactory.getLogger(RedisConfig.class); @Value("${spring.redis.host}")
    private String redisHost;
    @Value("${spring.redis.port}")
    private int redisPort;
    @Value("${spring.redis.timeout}")
    private int redisTimeout;
    @Value("${spring.redis.password}")
    private String redisAuth;
    @Value("${spring.redis.database}")
    private int redisDb;
    @Value("${spring.redis.pool.max-active}")
    private int maxActive;
    @Value("${spring.redis.pool.max-wait}")
    private int maxWait;
    @Value("${spring.redis.pool.max-idle}")
    private int maxIdle;
    @Value("${spring.redis.pool.min-idle}")
    private int minIdle;
    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        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());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                returnsb.toString(); }}; } @Bean public CacheManagerredisCacheManager() { RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate()); / / the default 300 seconds expired cacheManager. SetDefaultExpiration (300); / / start loading remote cache cacheManager. SetLoadRemoteCachesOnStartup (true); / / whether or not to use the prefix generator cacheManager. SetUsePrefix (true);
        return cacheManager;
    }
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(maxActive);
        poolConfig.setMaxIdle(maxIdle);
        poolConfig.setMaxWaitMillis(maxWait);
        poolConfig.setMinIdle(minIdle);
        poolConfig.setTestOnBorrow(true);
        poolConfig.setTestOnReturn(false);
        poolConfig.setTestWhileIdle(true);
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(poolConfig);
        jedisConnectionFactory.setPassword(redisAuth);
        jedisConnectionFactory.setHostName(redisHost);
        jedisConnectionFactory.setDatabase(redisDb);
        jedisConnectionFactory.setPort(redisPort);
        jedisConnectionFactory.setTimeout(redisTimeout);
        return jedisConnectionFactory;
    }
    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        Jackson2JsonRedisSerializer<Object> serializer = jackson2JsonRedisSerializer();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(serializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(serializer);
        return redisTemplate;
    }
    @Bean
    public Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
        final Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        final ObjectMapper objectMapper = Jackson2ObjectMapperBuilder
                .json().build();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        returnjackson2JsonRedisSerializer; }}Copy the code

Fill in the appropriate parameters for application.properties

1.3. Use

1.3.1. Pit 1

  1. Currently, the main use is caching and delete caching
@Cacheable(sync = true, value = "on_hospital_list", key = "'3003101006_'+#requestReport.body['carer_id']", condition = "#requestReport.body['carer_id'] ! = "") @Override public ResponseReport getHospitalList(RequestReport requestReport) { ResponseReport responseReport = new ResponseReport(); .return responseReport.returnSuccessResult(hospitals, "Hospital list obtained successfully", requestReport);
    }
Copy the code
  1. The inexperienced might struggle for a long time because I’m wrapping the input object with a JSONObject or map as the body value, and I’m initially writing requestReport.body.carer_id, but this will result in the following error
EL1008E: object of type 'com.alibaba.fastjson.JSONObject' - maybe not public
Copy the code

But you look for the answer on the Internet, it is not the right question, or other errors lead to the same error, anyway, I can not find the right answer

  1. #requestReport.body[‘carer_id’]

1.3.2. Pit 2

  1. To delete the cache, I’ve made a custom annotation because CacheEvict doesn’t seem to provide a way to delete multiple keys
//        @CacheEvict(value = "on_hospital_list", key="'3003101006_'+#requestReport.body['carer_id']")
    @CacheRemove(value = "on_hospital_list"/*,key={"'3003101006_'+#requestReport.body['carer_id']"."'3003101007_'+#requestReport.body['carer_id']"}*/) @override public ResponseReport (RequestReport RequestReport) {... The business logicreturn responseReport.returnError("9999"."Offline failed", requestReport);
    }
Copy the code
  1. annotations
@target ({elementtype.method}) @Retention(retentionPolicy.runtime) public @interface CacheRemove {/** * Category to be deleted For example Autocms all caches * * @return
     */
    String value() default ""; /** * The specific forehead type to be cleared ** @return
     */
    String[] key() default {};
}
Copy the code
  1. Annotations to realize
import com.zhiyis.framework.annotation.CacheRemove; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * @author laoliangliang * @date 2019/1/14 16:04 */ @component@aspect public class CacheRemoveAspect { Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired RedisTemplate<String, String> redis; ExpressionParser parser = new SpelExpressionParser(); LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer(); /** * Intercept methods marked @cacheremove */ @pointcut (value ="(execution(* *.*(..) ) && @annotation(com.zhiyis.framework.annotation.CacheRemove))")
    private void pointcut*/ AfterReturning(value =) {return return (value =) {return return (value =)"pointcut()") private void process(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method = signature.getMethod(); CacheRemove CacheRemove = method.getannotation (cacheremove.class); / / comment parsing String [] params = discoverer. GetParameterNames (method); EvaluationContext context = new StandardEvaluationContext();for (int len = 0; len < params.length; len++) {
            context.setVariable(params[len], args[len]);
        }
        if(cacheRemove ! = null) { StringBuilder sb = new StringBuilder(); String value = cacheRemove.value();if(! value.equals("")) { sb.append(value); } // Delete key String[] keys = cacheremove.key (); sb.append(":");
            for(String key : keys) { Expression expression = parser.parseExpression(key); String value1 = expression.getValue(context, String.class); CleanRedisCache (sb.tostring () + value1); } } } private void cleanRedisCache(String key) {if(key ! Redis. Delete (key); logger.info("Clear" + key + "Cache"); }}}Copy the code
  1. The annotation here writes parameters, and if you want to use an SPEL expression, you write a piece of code that parses the annotation

1. SpringCache fails in practice

1.1. The pom

  1. There are mainly the following two
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <! <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>Copy the code

1.2. Redis configuration

package com.zhiyis.common.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import redis.clients.jedis.JedisPoolConfig; import java.lang.reflect.Method; @Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport { private static Logger logger =  LoggerFactory.getLogger(RedisConfig.class); @Value("${spring.redis.host}")
    private String redisHost;
    @Value("${spring.redis.port}")
    private int redisPort;
    @Value("${spring.redis.timeout}")
    private int redisTimeout;
    @Value("${spring.redis.password}")
    private String redisAuth;
    @Value("${spring.redis.database}")
    private int redisDb;
    @Value("${spring.redis.pool.max-active}")
    private int maxActive;
    @Value("${spring.redis.pool.max-wait}")
    private int maxWait;
    @Value("${spring.redis.pool.max-idle}")
    private int maxIdle;
    @Value("${spring.redis.pool.min-idle}")
    private int minIdle;
    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        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());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                returnsb.toString(); }}; } @Bean public CacheManagerredisCacheManager() { RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate()); / / the default 300 seconds expired cacheManager. SetDefaultExpiration (300); / / start loading remote cache cacheManager. SetLoadRemoteCachesOnStartup (true); / / whether or not to use the prefix generator cacheManager. SetUsePrefix (true);
        return cacheManager;
    }
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(maxActive);
        poolConfig.setMaxIdle(maxIdle);
        poolConfig.setMaxWaitMillis(maxWait);
        poolConfig.setMinIdle(minIdle);
        poolConfig.setTestOnBorrow(true);
        poolConfig.setTestOnReturn(false);
        poolConfig.setTestWhileIdle(true);
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(poolConfig);
        jedisConnectionFactory.setPassword(redisAuth);
        jedisConnectionFactory.setHostName(redisHost);
        jedisConnectionFactory.setDatabase(redisDb);
        jedisConnectionFactory.setPort(redisPort);
        jedisConnectionFactory.setTimeout(redisTimeout);
        return jedisConnectionFactory;
    }
    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        Jackson2JsonRedisSerializer<Object> serializer = jackson2JsonRedisSerializer();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(serializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(serializer);
        return redisTemplate;
    }
    @Bean
    public Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
        final Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        final ObjectMapper objectMapper = Jackson2ObjectMapperBuilder
                .json().build();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        returnjackson2JsonRedisSerializer; }}Copy the code

Fill in the appropriate parameters for application.properties

1.3. Use

1.3.1. Pit 1

  1. Currently, the main use is caching and delete caching
@Cacheable(sync = true, value = "on_hospital_list", key = "'3003101006_'+#requestReport.body['carer_id']", condition = "#requestReport.body['carer_id'] ! = "") @Override public ResponseReport getHospitalList(RequestReport requestReport) { ResponseReport responseReport = new ResponseReport(); .return responseReport.returnSuccessResult(hospitals, "Hospital list obtained successfully", requestReport);
    }
Copy the code
  1. The inexperienced might struggle for a long time because I’m wrapping the input object with a JSONObject or map as the body value, and I’m initially writing requestReport.body.carer_id, but this will result in the following error
EL1008E: object of type 'com.alibaba.fastjson.JSONObject' - maybe not public
Copy the code

But you look for the answer on the Internet, it is not the right question, or other errors lead to the same error, anyway, I can not find the right answer

  1. #requestReport.body[‘carer_id’]

1.3.2. Pit 2

  1. To delete the cache, I’ve made a custom annotation because CacheEvict doesn’t seem to provide a way to delete multiple keys
//        @CacheEvict(value = "on_hospital_list", key="'3003101006_'+#requestReport.body['carer_id']")
    @CacheRemove(value = "on_hospital_list"/*,key={"'3003101006_'+#requestReport.body['carer_id']"."'3003101007_'+#requestReport.body['carer_id']"}*/) @override public ResponseReport (RequestReport RequestReport) {... The business logicreturn responseReport.returnError("9999"."Offline failed", requestReport);
    }
Copy the code
  1. annotations
@target ({elementtype.method}) @Retention(retentionPolicy.runtime) public @interface CacheRemove {/** * Category to be deleted For example Autocms all caches * * @return
     */
    String value() default ""; /** * The specific forehead type to be cleared ** @return
     */
    String[] key() default {};
}
Copy the code
  1. Annotations to realize
import com.zhiyis.framework.annotation.CacheRemove; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * @author laoliangliang * @date 2019/1/14 16:04 */ @component@aspect public class CacheRemoveAspect { Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired RedisTemplate<String, String> redis; ExpressionParser parser = new SpelExpressionParser(); LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer(); /** * Intercept methods marked @cacheremove */ @pointcut (value ="(execution(* *.*(..) ) && @annotation(com.zhiyis.framework.annotation.CacheRemove))")
    private void pointcut*/ AfterReturning(value =) {return return (value =) {return return (value =)"pointcut()") private void process(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method = signature.getMethod(); CacheRemove CacheRemove = method.getannotation (cacheremove.class); / / comment parsing String [] params = discoverer. GetParameterNames (method); EvaluationContext context = new StandardEvaluationContext();for (int len = 0; len < params.length; len++) {
            context.setVariable(params[len], args[len]);
        }
        if(cacheRemove ! = null) { StringBuilder sb = new StringBuilder(); String value = cacheRemove.value();if(! value.equals("")) { sb.append(value); } // Delete key String[] keys = cacheremove.key (); sb.append(":");
            for(String key : keys) { Expression expression = parser.parseExpression(key); String value1 = expression.getValue(context, String.class); CleanRedisCache (sb.tostring () + value1); } } } private void cleanRedisCache(String key) {if(key ! Redis. Delete (key); logger.info("Clear" + key + "Cache"); }}}Copy the code
  1. The annotation here writes parameters, and if you want to use an SPEL expression, you write a piece of code that parses the annotation

854393687 

Group provides free Java architecture learning materials (which have high availability, high concurrency, high performance and distributed, Jvm performance tuning, Spring source code, MyBatis, Netty, Redis, Kafka, Mysql, Zookeeper, Tomcat, Docker, Dubbo, multiple knowledge architecture data, such as the Nginx) reasonable use their every minute and second time to learn to improve yourself, don’t use “no time” to hide his ideas on the lazy! While young, hard to fight, to the future of their own account!