1. SpringCache实战遇坑

1.1. pom

  1. 主要是以下两个
  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-data-redis</artifactId>
  4. </dependency>
  5. <!-- 配合redis做缓存 -->
  6. <dependency>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-cache</artifactId>
  9. </dependency>

1.2. Redis配置

  1. package com.zhiyis.common.config;
  2. import com.fasterxml.jackson.annotation.JsonAutoDetect;
  3. import com.fasterxml.jackson.annotation.PropertyAccessor;
  4. import com.fasterxml.jackson.databind.ObjectMapper;
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7. import org.springframework.beans.factory.annotation.Value;
  8. import org.springframework.cache.CacheManager;
  9. import org.springframework.cache.annotation.CachingConfigurerSupport;
  10. import org.springframework.cache.annotation.EnableCaching;
  11. import org.springframework.cache.interceptor.KeyGenerator;
  12. import org.springframework.context.annotation.Bean;
  13. import org.springframework.context.annotation.Configuration;
  14. import org.springframework.data.redis.cache.RedisCacheManager;
  15. import org.springframework.data.redis.connection.RedisConnectionFactory;
  16. import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
  17. import org.springframework.data.redis.core.RedisTemplate;
  18. import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
  19. import org.springframework.data.redis.serializer.StringRedisSerializer;
  20. import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
  21. import redis.clients.jedis.JedisPoolConfig;
  22. import java.lang.reflect.Method;
  23. @Configuration
  24. @EnableCaching
  25. public class RedisConfig extends CachingConfigurerSupport {
  26. private static Logger logger = LoggerFactory.getLogger(RedisConfig.class);
  27. @Value("${spring.redis.host}")
  28. private String redisHost;
  29. @Value("${spring.redis.port}")
  30. private int redisPort;
  31. @Value("${spring.redis.timeout}")
  32. private int redisTimeout;
  33. @Value("${spring.redis.password}")
  34. private String redisAuth;
  35. @Value("${spring.redis.database}")
  36. private int redisDb;
  37. @Value("${spring.redis.pool.max-active}")
  38. private int maxActive;
  39. @Value("${spring.redis.pool.max-wait}")
  40. private int maxWait;
  41. @Value("${spring.redis.pool.max-idle}")
  42. private int maxIdle;
  43. @Value("${spring.redis.pool.min-idle}")
  44. private int minIdle;
  45. @Bean
  46. @Override
  47. public KeyGenerator keyGenerator() {
  48. return new KeyGenerator() {
  49. @Override
  50. public Object generate(Object target, Method method, Object... params) {
  51. StringBuilder sb = new StringBuilder();
  52. sb.append(target.getClass().getName());
  53. sb.append(method.getName());
  54. for (Object obj : params) {
  55. sb.append(obj.toString());
  56. }
  57. return sb.toString();
  58. }
  59. };
  60. }
  61. @Bean
  62. public CacheManager redisCacheManager() {
  63. RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate());
  64. //默认300秒过期
  65. cacheManager.setDefaultExpiration(300);
  66. // 启动时加载远程缓存
  67. cacheManager.setLoadRemoteCachesOnStartup(true);
  68. //是否使用前缀生成器
  69. cacheManager.setUsePrefix(true);
  70. return cacheManager;
  71. }
  72. @Bean
  73. public RedisConnectionFactory redisConnectionFactory() {
  74. JedisPoolConfig poolConfig = new JedisPoolConfig();
  75. poolConfig.setMaxTotal(maxActive);
  76. poolConfig.setMaxIdle(maxIdle);
  77. poolConfig.setMaxWaitMillis(maxWait);
  78. poolConfig.setMinIdle(minIdle);
  79. poolConfig.setTestOnBorrow(true);
  80. poolConfig.setTestOnReturn(false);
  81. poolConfig.setTestWhileIdle(true);
  82. JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(poolConfig);
  83. jedisConnectionFactory.setPassword(redisAuth);
  84. jedisConnectionFactory.setHostName(redisHost);
  85. jedisConnectionFactory.setDatabase(redisDb);
  86. jedisConnectionFactory.setPort(redisPort);
  87. jedisConnectionFactory.setTimeout(redisTimeout);
  88. return jedisConnectionFactory;
  89. }
  90. @Bean
  91. public RedisTemplate<String, Object> redisTemplate() {
  92. RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
  93. Jackson2JsonRedisSerializer<Object> serializer = jackson2JsonRedisSerializer();
  94. redisTemplate.setConnectionFactory(redisConnectionFactory());
  95. redisTemplate.setKeySerializer(new StringRedisSerializer());
  96. redisTemplate.setValueSerializer(serializer);
  97. redisTemplate.setHashKeySerializer(new StringRedisSerializer());
  98. redisTemplate.setHashValueSerializer(serializer);
  99. return redisTemplate;
  100. }
  101. @Bean
  102. public Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
  103. final Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
  104. final ObjectMapper objectMapper = Jackson2ObjectMapperBuilder
  105. .json().build();
  106. objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  107. objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  108. jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
  109. return jackson2JsonRedisSerializer;
  110. }
  111. }

在application.properties填上相应的参数

1.3. 使用

1.3.1. 坑1

  1. 目前主要使用的就是缓存和删除缓存
  1. @Cacheable(sync = true, value = "on_hospital_list", key = "'3003101006_'+#requestReport.body['carer_id']", condition = "#requestReport.body['carer_id'] != '' ")
  2. @Override
  3. public ResponseReport getHospitalList(RequestReport requestReport) {
  4. ResponseReport responseReport = new ResponseReport();
  5. 。。。
  6. return responseReport.returnSuccessResult(hospitals, "获取医院列表成功", requestReport);
  7. }
  1. 这里没有经验的人可能会纠结很久,因为我封装的入参对象,里面放的是JSONObject或者map作为的body值,这里我一开始是写成requestReport.body.carer_id这样的,但是这样会报如下错误
  1. EL1008E: object of type 'com.alibaba.fastjson.JSONObject' - maybe not public

但你在网上找答案,都是文不对题,或者说其他错误导致相同的报错,反正我是找不到正确的解答

3. 解决方法就是如上代码,直接写成#requestReport.body['carer_id']

1.3.2. 坑2

  1. 删除缓存,我自定义了一个注解,原因是好像CacheEvict没提供删除多个key的方法
  1. // @CacheEvict(value = "on_hospital_list", key="'3003101006_'+#requestReport.body['carer_id']")
  2. @CacheRemove(value = "on_hospital_list"/*,key={"'3003101006_'+#requestReport.body['carer_id']","'3003101007_'+#requestReport.body['carer_id']"}*/)
  3. @Override
  4. public ResponseReport upDownServer(RequestReport requestReport) {
  5. 。。。业务逻辑
  6. return responseReport.returnError("9999", "上下线失败", requestReport);
  7. }
  1. 注解
  1. @Target({ElementType.METHOD})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface CacheRemove {
  4. /**
  5. * 需要清除的大类 例如 autocms 所有缓存
  6. *
  7. * @return
  8. */
  9. String value() default "";
  10. /**
  11. * 需要清除的具体的额类型
  12. *
  13. * @return
  14. */
  15. String[] key() default {};
  16. }
  1. 注解实现

  1. import com.zhiyis.framework.annotation.CacheRemove;
  2. import org.aspectj.lang.JoinPoint;
  3. import org.aspectj.lang.annotation.AfterReturning;
  4. import org.aspectj.lang.annotation.Aspect;
  5. import org.aspectj.lang.annotation.Pointcut;
  6. import org.aspectj.lang.reflect.MethodSignature;
  7. import org.slf4j.Logger;
  8. import org.slf4j.LoggerFactory;
  9. import org.springframework.beans.factory.annotation.Autowired;
  10. import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
  11. import org.springframework.data.redis.core.RedisTemplate;
  12. import org.springframework.expression.EvaluationContext;
  13. import org.springframework.expression.Expression;
  14. import org.springframework.expression.ExpressionParser;
  15. import org.springframework.expression.spel.standard.SpelExpressionParser;
  16. import org.springframework.expression.spel.support.StandardEvaluationContext;
  17. import org.springframework.stereotype.Component;
  18. import java.lang.reflect.Method;
  19. /**
  20. * 清除缓存切面类
  21. *
  22. * @author laoliangliang
  23. * @date 2019/1/14 16:04
  24. */
  25. @Component
  26. @Aspect
  27. public class CacheRemoveAspect {
  28. Logger logger = LoggerFactory.getLogger(this.getClass());
  29. @Autowired
  30. RedisTemplate<String, String> redis;
  31. ExpressionParser parser = new SpelExpressionParser();
  32. LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
  33. /**
  34. * 截获标有@CacheRemove的方法
  35. */
  36. @Pointcut(value = "(execution(* *.*(..)) && @annotation(com.zhiyis.framework.annotation.CacheRemove))")
  37. private void pointcut() {
  38. }
  39. /**
  40. * 功能描述: 切面在截获方法返回值之后
  41. */
  42. @AfterReturning(value = "pointcut()")
  43. private void process(JoinPoint joinPoint) {
  44. Object[] args = joinPoint.getArgs();
  45. //获取切入方法的数据
  46. MethodSignature signature = (MethodSignature) joinPoint.getSignature();
  47. //获取切入方法
  48. Method method = signature.getMethod();
  49. //获得注解
  50. CacheRemove cacheRemove = method.getAnnotation(CacheRemove.class);
  51. //注解解析
  52. String[] params = discoverer.getParameterNames(method);
  53. EvaluationContext context = new StandardEvaluationContext();
  54. for (int len = 0; len < params.length; len++) {
  55. context.setVariable(params[len], args[len]);
  56. }
  57. if (cacheRemove != null) {
  58. StringBuilder sb = new StringBuilder();
  59. String value = cacheRemove.value();
  60. if (!value.equals("")) {
  61. sb.append(value);
  62. }
  63. //需要移除的正则key
  64. String[] keys = cacheRemove.key();
  65. sb.append(":");
  66. for (String key : keys) {
  67. Expression expression = parser.parseExpression(key);
  68. String value1 = expression.getValue(context, String.class);
  69. //指定清除的key的缓存
  70. cleanRedisCache(sb.toString() + value1);
  71. }
  72. }
  73. }
  74. private void cleanRedisCache(String key) {
  75. if (key != null) {
  76. //删除缓存
  77. redis.delete(key);
  78. logger.info("清除 " + key + " 缓存");
  79. }
  80. }
  81. }
  1. 这里的注解写入参数,如果想要使用spel表达式,要写上解析注解的一段代码

参考

https://huan1993.iteye.com/blog/2395239

http://www.cnblogs.com/imyijie/p/6518547.html

SpringCache实战遇坑的更多相关文章

  1. redis 集群 遇坑1

    redis 集群 遇坑1 redis集群需要开2个端口 一个是客户端连接端口 一个是 集群总线端口 集群总线端口 是 客户端端口 + 10000 如 客户端端口是 6380 则集群总线端口 为 163 ...

  2. rabbitmq在ios中实战采坑

    1. rabbitmq在ios中实战采坑 1.1. 问题 ios使用rabbitmq连接,没过多久就断开,并报错.且用android做相同的步骤并不会报错,错误如下 Received connecti ...

  3. 浅谈Android Studio3.0更新之路(遇坑必入)

    >可以参考官网设置-> 1 2 >> Fantasy_Lin_网友评论原文地址是:简书24K纯帅豆写的我也更新一下出处[删除]Fa 转自脚本之家 浅谈Android Studi ...

  4. Android 上传开源项目到 jcenter 实战踩坑之路

    本文微信公众号「AndroidTraveler」首发. 背景 其实 Android 上传开源项目到 jcenter 并不是一件新鲜事,网上也有很多文章. 包括我本人在将开源项目上传到 jcenter ...

  5. Cat搭建遇坑记

    1. Cat搭建遇坑记 1.1. 报错 服务端启动 Unable to get component: class com.dianping.cat.analysis.TcpSocketReceiver ...

  6. deno+mongo实战踩坑记

    自从 deno 1.0 发布以来,有关 deno 的文章很多,大多数都是在讨论怎么安装 deno .deno 有哪些特点 .deno 和 node 有哪些异同.deno是不是 node 的替代品等.咱 ...

  7. Windows安装Scrapy遇坑解决办

    PS: Windows真心不适合开发.且行且珍惜.... 坑: error: Setup script exited with error: Microsoft Visual C++ 9.0 is r ...

  8. Java之戳中痛点 - (6)避免类型自动转换,例如两个整数相除得浮点数遇坑

    先来看一个例子: package com.test; public class calculate { /** * 光速30万公里/秒 */ public static final int LIGHT ...

  9. Android组件化demo实现以及遇坑分享

    首先贴出demo的github地址:GitHub - TenzLiu/TenzModuleDemo: android组件化demo 作者:TenzLiu原文链接:https://www.jianshu ...

随机推荐

  1. [转]vue跨域解决方法

      vue跨域解决方法 vue项目中,前端与后台进行数据请求或者提交的时候,如果后台没有设置跨域,前端本地调试代码的时候就会报“No 'Access-Control-Allow-Origin' hea ...

  2. mybatis学习笔记1.零碎记录

    1.conf.xml文件中的一些标签先后顺序会有影响. conf.xml文件<configuration>标签对里面配置的<typeAliases>标签的位置还有讲究?我将其放 ...

  3. python、java读数据

    python从txt文档中读数据有个特别神奇的函数 可以把txt文档中的数据直接读取成python数组 java用Scanner类读数据比较方便

  4. python 字符串 转 bit, bitarray 异或加密

    Python中异或加密要将str 转为 bitarray, 提示: int类型和纯数字的字符串也可以异或处理, 可能更方便 from bitarray import bitarray def str2 ...

  5. 20170529计划---统计业务量并生成EXCEL通过邮件发送

    每个月都要统计这些业务量的东东,烦死了,赶紧通过python写一个来搞定吧,三天搞定吧,未完待续哈. 2017-5-29 19:50粗略地做了一个思维导图哈 终于第三天完成啦 #encoding=ut ...

  6. sui.js和workflow2.js内容详解

    一. 二. var config=$("div[name=lwnf]").sui().getConfig()~var config = this.zoo.getConfig();等 ...

  7. 第三周助教工作总结——NWNU李泓毅

    本周点评作业数量:第一部分是第一篇博客的剩余部分,给出了共计22份作业的具体分数.第二部分是第二篇博客的已提交部分共计19份作业. 这是我的博客地址:https://www.cnblogs.com/N ...

  8. P3806 【模板】点分治1

    一道淀粉质的模版题,开始是暴力 #include <bits/stdc++.h> #define up(i,l,r) for(register int i = (l); i <= ( ...

  9. [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.2:compile (default-compile) on project taotao-manager-pojo: Compilation failure

    运行maven项目时报错 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.2:compi ...

  10. html5中如何更改、去掉input type默认样式

    1.如何去掉input type=date 默认样式 HTML代码: 选择日期:<input type="date" value="2017-06-01" ...