一、环境 Redis:4.0.9 SpringBoot:2.0.1 Redis安装:Linux(Redhat)安装Redis 二、SpringBoot整合Redis 1、项目基本搭建: 我们基于(五)SpringBoot2.0基础篇- Mybatis与插件生成代码 该项目来做Redis整合; 2、添加maven相关依赖和Redis的连接信息: Pom.xml ![复制代码](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC)
org.springframework.boot
spring-boot-starter-redis
1.4.7.RELEASE
com.alibaba
fastjson
1.2.28
org.springframework.boot
spring-boot-starter-aop
![复制代码](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC)
application.properties: spring.redis.cluster.nodes=192.168.1.124:7001 3、创建RedisProperties属性类和RedisConfig配置类,将JedisCluster放入Spring容器中: RedisConfigurationProperties:![复制代码](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC) package com.cn.common.redis;import java.util.ArrayList;import java.util.List;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.context.annotation.Configuration;/**
* @program: spring-boot-example
* @description:
* @author:
* @create: 2018-05-16 15:15
**/@Configuration
@ConfigurationProperties(prefix = "spring.redis.cluster")public class RedisConfigurationProperties { private List nodes = new ArrayList(); public List getNodes() { return nodes;
} public void setNodes(List nodes) { this.nodes = nodes;
}
}![复制代码](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC) RedisConfig:![复制代码](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC) package com.cn.common.redis;import java.util.HashSet;import java.util.Set;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import redis.clients.jedis.HostAndPort;import redis.clients.jedis.JedisCluster;/**
* @program: spring-boot-example
* @description: Redis的配置文件
* @author:
* @create: 2018-05-16 15:01
**/@Configurationpublic class RedisConfig {
@Autowired private RedisConfigurationProperties redisConfigurationProperties;
@Bean public JedisCluster jedisCluster() {
Set nodeSet = new HashSet(); for(String node :redisConfigurationProperties.getNodes()) {
String[] split = node.split(":");
nodeSet.add(new HostAndPort(split[0],Integer.valueOf(split[1])));
} return new JedisCluster(nodeSet);
}
}![复制代码](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC)
4、创建封装Redis的增删改查(JedisService,JedisServiceImpl): ![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC) ![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC) package com.cn.common.service;import java.util.List;import java.util.Map;import redis.clients.jedis.GeoRadiusResponse;/**
* @program: spring-boot-example
* @description:
* @author:
* @create: 2018-05-16 15:27
**/public interface JedisService { /**
* @Description: 是否存在
* @Param:
* @return:
* @Author:
* @Date: 2018/5/16 */
boolean exists(String key); /**
* @Description:缓存set值
* @Param: seconds:缓存时间,不设置则为0
* @return:
* @Author:
* @Date: 2018/5/16 */
String set(String key,String value,int seconds); /**
* @Description: 重新缓存getSet值
* @Param:
* @return:
* @Author:
* @Date: 2018/5/16 */
String getSet(String key,String value, int seconds); /**
* @Description: 获取set值
* @Param:
* @return:
* @Author:
* @Date: 2018/5/16 */
String get(String key); /**
* @Description: 添加地理位置
* @Param:
* @return:
* @Author:
* @Date: 2018/5/16 */
Long geoadd(String key,double longitude,double latitude,byte[] obj); /**
* @Description: 地理位置查询
* @Param:
* @return:
* @Author:
* @Date: 2018/5/16 */
List georadius(String key,double longitude,double latitude);
/**
* @Description: 删除key
* @Param:
* @return:
* @Author:
* @Date: 2018/5/16
*/
void delKey(String key);
/**
* @Description: 删除native key
* @Param:
* @return:
* @Author:
* @Date: 2018/5/16
*/
void delNativeKey(String key);
/**
* @Description: 获取map格式的数据
* @Param:
* @return:
* @Author:
* @Date: 2018/5/16
*/
Map getMapData(String key);
/**
* @Description: 加锁,避免重复提交
* @Param:
* @return:
* @Author:
* @Date: 2018/5/16
*/
boolean lock(String key,int seconds);
/**
* @Description: 解锁
* @Param:
* @return:
* @Author:
* @Date: 2018/5/16
*/
void unlock(String key);
/**
* @Description: 统计锁定次数
* @Param:
* @return:
* @Author:
* @Date: 2018/5/16
*/
String getLocakValue(String key);
}JedisService.java ![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC) ![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC) package com.cn.common.service;import com.alibaba.fastjson.JSON;import java.util.List;import java.util.Map;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import redis.clients.jedis.GeoRadiusResponse;import redis.clients.jedis.JedisCluster;/**
* @program: spring-boot-example
* @description:
* @author:
* @create: 2018-05-16 15:45
**/@Servicepublic class JedisServiceImpl implements JedisService {
@Autowired private JedisCluster jedisCluster;
@Override public boolean exists(String key) { boolean flag = false;
flag = jedisCluster.exists(key); return flag;
}
@Override public String set(String key, String value, int seconds) {
String responseResult = jedisCluster.set(key,value); if(seconds!=0)
jedisCluster.expire(key,seconds); return responseResult;
}
@Override public String getSet(String key, String value, int seconds) {
String jedisClusterSet = jedisCluster.getSet(key, value);
jedisCluster.expire(key,seconds); return jedisClusterSet;
}
@Override public String get(String key) {
String str = jedisCluster.get(key); return str;
}
@Override public Long geoadd(String key, double longitude, double latitude, byte[] obj) { return null;
}
@Override public List georadius(String key, double longitude, double latitude) { return null;
}
@Override public void delKey(String key) {
jedisCluster.del(key);
}
@Override public void delNativeKey(String key) {
jedisCluster.del(key);
}
@Override public Map getMapData(String key) {
String str = jedisCluster.get(key);
Map map = JSON.parseObject(str, Map.class); return map;
} /**
* @Description: 如为第一次,则加上锁,每次调用值会自动加1
* @Param:
* @return:
* @Author:
* @Date: 2018/5/16
*/
@Override public boolean lock(String key, int seconds) { if(jedisCluster.incr(key)==1) {
jedisCluster.expire(key,seconds); return false;
} return true;
}
@Override public void unlock(String key) {
jedisCluster.del(key);
}
@Override public String getLocakValue(String key) { return jedisCluster.get(key);
}
}JedisServiceImpl.java 5、创建注解类和切面类(我使用注解来实现缓存的set和get): RedisCache:![复制代码](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC) package com.cn.common.redis;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/**
* @Description: 加上该注解,代理service命中缓存则从缓存中读取数据,否则从service业务逻辑获得,并存入缓存
* @Param:
* @return:
* @Author:
* @Date: 2018/5/16 */@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
@Documentedpublic @interface RedisCache { /**
* @Description: 数据返回类型
* @Param:
* @return:
* @Author:
* @Date: 2018/5/16 */
Class type(); /**
* @Description: 数据缓存时间单位s秒
* @Param: 默认10分钟
* @return:
* @Author:
* @Date: 2018/5/16 */
int cacheTime() default 600;
}![复制代码](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC)
RedisCacheAspect: ![复制代码](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC) package com.cn.common.redis;import com.alibaba.fastjson.JSON;import com.cn.common.service.JedisService;import java.lang.reflect.Method;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.Signature;import org.aspectj.lang.annotation.Around;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.stereotype.Component;/**
* @program: spring-boot-example
* @description:
* @author:
* @create: 2018-05-16 16:29
**/@Aspect
@Componentpublic class RedisCacheAspect { private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired private JedisService jedisService;
@Pointcut("execution(public * com.cn.service..*.*(..))") public void webAspect(){}
@Around("webAspect()") public Object redisCache(ProceedingJoinPoint pjp) throws Throwable { //得到类名、方法名和参数
String redisResult = "";
String className = pjp.getTarget().getClass().getName();
String methodName = pjp.getSignature().getName();
Object[] args = pjp.getArgs(); //根据类名,方法名和参数生成key
String key = genKey(className,methodName,args);
logger.info("生成的key[{}]",key); //得到被代理的方法
Signature signature = pjp.getSignature(); if(!(signature instanceof MethodSignature)){ throw new IllegalArgumentException();
}
MethodSignature methodSignature = (MethodSignature) signature;
Method method = pjp.getTarget().getClass().getMethod(methodSignature.getName(),methodSignature.getParameterTypes()); //得到被代理的方法上的注解
Class modelType = method.getAnnotation(RedisCache.class).type(); int cacheTime = method.getAnnotation(RedisCache.class).cacheTime();
Object result = null; if(!jedisService.exists(key)) {
logger.info("缓存未命中"); //缓存不存在,则调用原方法,并将结果放入缓存中
result = pjp.proceed(args);
redisResult = JSON.toJSONString(result);
jedisService.set(key,redisResult,cacheTime);
} else{ //缓存命中
logger.info("缓存命中");
redisResult = jedisService.get(key); //得到被代理方法的返回值类型
Class returnType = method.getReturnType();
result = JSON.parseObject(redisResult,returnType);
} return result;
} /**
* @Description: 生成key
* @Param:
* @return:
* @Author:
* @Date: 2018/5/16 */
private String genKey(String className, String methodName, Object[] args) {
StringBuilder sb = new StringBuilder("SpringBoot:");
sb.append(className);
sb.append("_");
sb.append(methodName);
sb.append("_"); for (Object object: args) {
logger.info("obj:"+object); if(object!=null) {
sb.append(object+"");
sb.append("_");
}
} return sb.toString();
}
}![复制代码](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC)
6、在StudentServiceImpl中加入缓存注释: StudentServiceImpl: ![复制代码](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC) package com.cn.service;import com.cn.common.redis.RedisCache;import com.cn.entity.Student;import com.cn.mapper.StudentMapper;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;/**
* @program: spring-boot-example
* @description:
* @author:
* @create: 2018-05-11 10:55
**/@Servicepublic class StudentServiceImpl implements StudentService{
@Autowired private StudentMapper studentMapper;
@Override
@RedisCache(type = Student.class) public Student getStudentByPrimaryKey(int id) { return studentMapper.selectByPrimaryKey(id);
}
}![复制代码](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC)
7、启动测试: 第一次调用: ![https://img3.sycdn.imooc.com/5b16672e0001eb3409600569.jpg](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC) 查看控制台: ![https://img1.sycdn.imooc.com/5b16673700013e2b12980138.jpg](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC) ![https://img4.sycdn.imooc.com/5b16673f0001e63e11940115.jpg](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC) 第二次调用: ![https://img2.sycdn.imooc.com/5b1667460001a2b309260539.jpg](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC) 查看控制台: ![https://img1.sycdn.imooc.com/5b16675000011b9f13550168.jpg](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC) 发现第二次未打印出MyBatis的查询日志,并且显示缓存命中,通过RedisDeskManager工具查看Redis缓存: ![https://img2.sycdn.imooc.com/5b16676e0001096b11320157.jpg](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC) 实例代码:https://gitee.com/lfalex/spring-boot-example/tree/dev/spring-boot-mybatis-redis 原文出处
|