1. SpringCache实战遇坑

1.1. pom

  1. 主要是以下两个
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 配合redis做缓存 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>

1.2. Redis配置

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());
}
return sb.toString();
}
};
} @Bean
public CacheManager redisCacheManager() {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate());
//默认300秒过期
cacheManager.setDefaultExpiration(300);
// 启动时加载远程缓存
cacheManager.setLoadRemoteCachesOnStartup(true);
//是否使用前缀生成器
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);
return jackson2JsonRedisSerializer;
}
}

在application.properties填上相应的参数

1.3. 使用

1.3.1. 坑1

  1. 目前主要使用的就是缓存和删除缓存
@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, "获取医院列表成功", requestReport);
}
  1. 这里没有经验的人可能会纠结很久,因为我封装的入参对象,里面放的是JSONObject或者map作为的body值,这里我一开始是写成requestReport.body.carer_id这样的,但是这样会报如下错误
EL1008E: object of type 'com.alibaba.fastjson.JSONObject' - maybe not public

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

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

1.3.2. 坑2

  1. 删除缓存,我自定义了一个注解,原因是好像CacheEvict没提供删除多个key的方法
//        @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 upDownServer(RequestReport requestReport) {
。。。业务逻辑 return responseReport.returnError("9999", "上下线失败", requestReport);
}
  1. 注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheRemove { /**
* 需要清除的大类 例如 autocms 所有缓存
*
* @return
*/
String value() default ""; /**
* 需要清除的具体的额类型
*
* @return
*/
String[] key() default {};
}
  1. 注解实现

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(); /**
* 截获标有@CacheRemove的方法
*/
@Pointcut(value = "(execution(* *.*(..)) && @annotation(com.zhiyis.framework.annotation.CacheRemove))")
private void pointcut() {
} /**
* 功能描述: 切面在截获方法返回值之后
*/
@AfterReturning(value = "pointcut()")
private void process(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
//获取切入方法的数据
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//获取切入方法
Method method = signature.getMethod();
//获得注解
CacheRemove cacheRemove = method.getAnnotation(CacheRemove.class); //注解解析
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);
}
//需要移除的正则key
String[] keys = cacheRemove.key();
sb.append(":");
for (String key : keys) {
Expression expression = parser.parseExpression(key);
String value1 = expression.getValue(context, String.class);
//指定清除的key的缓存
cleanRedisCache(sb.toString() + value1);
}
} } private void cleanRedisCache(String key) {
if (key != null) {
//删除缓存
redis.delete(key);
logger.info("清除 " + key + " 缓存");
}
}
}
  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. 记录在Ubuntu 18.04系统中安装Apache, MySQL和PHP环境

    虽然我们在Linux VPS.服务器安装WEB环境比较方便,可以选择面板或者一键包,但是有些我们需要深入学习的网友不会选择一键安装,而是会尝试编译安装.这样可以学到一些内在的技术.一般我们较为习惯选择 ...

  2. PAT A1010.Radix 二分法

    PAT A1010.Radix 链接: https://pintia.cn/problem-sets/994805342720868352/problems/994805507225665536 算法 ...

  3. Mybatis中的CDATA标签

    术语 CDATA 指的是不应由 XML 解析器进行解析的文本数据(Unparsed Character Data). 在 XML 元素中,"<" 和 "&& ...

  4. ajax用户是否存在

    $(function(){ $("#username").blur(function(){ var usernameInput=$(this).val(); $.post( &qu ...

  5. redis学习-列表(list)常用命令

    redis学习-列表(list)常用命令   lpush:从列表左侧头部添加数据 rpush:从右侧尾部添加数据 lpop:从给左侧头部取出一个元素 rpop:从右侧尾部取出一个元素 lrange:取 ...

  6. sjms-4 行为型模式

    行为型模式 责任链模式 内容:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止.角色:抽象处理者(Hand ...

  7. Django之路

    备注:本套笔记内容来源于互联网,只做学习使用,如有侵权请联系本笔记作者. 资料内容 Django之路(一)——什么是Web开发 Django之路(二)——Django初识 Django之路(三)——U ...

  8. mybatis 中使用oracle merger into

    项目背景:设计到excel导入,数据量也比较大,保证性能的情况下还要考虑到:如果数据中有这条数据的主键,则更新(update),不存在的情况,执行插入(insert). mybatis代码: < ...

  9. crontab计划不执行问题

    问题现象:编写了一个自动释放磁盘空间的脚本,并将其加入到crontab中.crontab显示如下:# crontab -l10 5 * * * bash /home/backup/bin/clear. ...

  10. Linux下好用的屏幕录像软件kazam及截图软件shutter

    都是apt直接安装即可使用. 其中kazam默认保存的文件格式是avi,非常大,通常录制几十秒就已经好几个G,导致录制过程太占用资源,会出现卡顿的现象. 在“首选项”中可以选择输出格式为mp4,文件就 ...