写在前面:
最近在使用springboot2.0,想整合一下redis做缓存,但是使用原生的,不大好用,所以就想自己将redis进一步的封装,,想着使用自定义注解来对数据进行缓存,,,
当你添加缓存的时候不指定keyName,默认使用的是全类名加上方法名与参数,删除的时候需要使用全类名加方法名
演示
先看看怎么用
1.引入此jar包,在配置文件配置redis基本信息
2.新建一个配置类集成RedisCacheAspect,实现方法,定义切入点表达式
3.在你需要缓存,删除缓存的地方,添加注解
4.OK
简单不。。看看原理
1.准备
首先这是一个分模块的项目,缓存是一个模块,service是一个模块,dal是一个模块,web是一个springboot项目。
先将项目创建好
2.缓存模块
1.缓存模块的pom文件
org.springframework.boot
spring-boot-starter-redis
1.4.7.RELEASE
org.springframework.boot
spring-boot-starter-aop
com.alibaba
fastjson
2.缓存模块的数据
RedisProperties
读取配置文件中的redis的配置,进行封装
@Configuration
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
private String host;
private String port;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
}
RedisConfig
将配置文件中的数据,转换成程序可用的jedis客户端
@Configuration
public class RedisConfig {
@Autowired
private RedisProperties redisProperties;
@Bean
public JedisPool jedisPool(){
String host = redisProperties.getHost();
Integer port = Integer.parseInt(redisProperties.getPort());
return new JedisPool(host,port);
}
public static String getPackages(){
return "niaho";
}
}
JedisClient
jedis客户端的接口
public interface JedisClient {
/**
* 设置key,value
*/
String set(String key, String value);
/**
* 设置key,value并设置过期时间
*/
String set(String key, String value, int time);
/**
* 根据key得到值
*/
String get(String key);
/**
* 根据key删除值
*/
Long del(String key);
/**
* 根据前缀得到所有的key
*/
Set keys(String key);
/**
* 判断key是否存在
*/
Boolean exists(String key);
/**
* 为key设置过期时间
*/
Long expire(String key, int seconds);
/**
* 得到key的存活时间 , key不存在-2, key永久存活-1 key存活时间(秒)
*/
Long ttl(String key);
/**
* 将key的值,加一
*/
Long incr(String key);
/**
* 设置map的值
*/
Long hset(String key, String field, String value);
/**
* 得到map的值
*/
String hget(String key, String field);
/**
* 删除map
*/
Long hdel(String key, String... field);
}
JedisClientPool
单机版jedis实现,
@Service
public class JedisClientPool implements JedisClient {
@Autowired
private JedisPool jedisPool;
@Override
public String set(String key, String value) {
Jedis jedis = jedisPool.getResource();
String result = jedis.set(key, value);
jedis.close();
return result;
}
@Override
public String set(String key, String value, int time){
Jedis jedis = jedisPool.getResource();
String set = jedis.set(key, value);
Long expire = expire(key, time);
return set;
}
@Override
public Long del(String key) {
Jedis jedis = jedisPool.getResource();
Long del = jedis.del(key);
jedis.close();
return del;
}
@Override
public Set keys(String key) {
Jedis jedis = jedisPool.getResource();
Set keys = jedis.keys(key);
return keys;
}
@Override
public String get(String key) {
Jedis jedis = jedisPool.getResource();
String result = jedis.get(key);
jedis.close();
return result;
}
@Override
public Boolean exists(String key) {
Jedis jedis = jedisPool.getResource();
Boolean result = jedis.exists(key);
jedis.close();
return result;
}
@Override
public Long expire(String key, int seconds) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.expire(key, seconds);
jedis.close();
return result;
}
@Override
public Long ttl(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.ttl(key);
jedis.close();
return result;
}
@Override
public Long incr(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.incr(key);
jedis.close();
return result;
}
@Override
public Long hset(String key, String field, String value) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hset(key, field, value);
jedis.close();
return result;
}
@Override
public String hget(String key, String field) {
Jedis jedis = jedisPool.getResource();
String result = jedis.hget(key, field);
jedis.close();
return result;
}
@Override
public Long hdel(String key, String... field) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hdel(key, field);
jedis.close();
return result;
}
}
RedisCache
使用的注解,在需要缓存的时候加上
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
@Documented
public @interface RedisCache {
/**
* @Description: 缓存的前缀
* @Param:
* @return:
* @Author:
* @Date: 2018/5/16
*/
String keyName() default "";
/**
* @Description: 数据缓存时间单位s秒
* @Param: 默认10分钟
* @return:
* @Author:
* @Date: 2018/5/16
*/
int cacheTime() default -1;
}
RedisCacheAspect
redis的切面类,核心类,当你添加了注解,需要进行缓存,或者删除缓存的时候,这个类进行操作
public class RedisCacheAspect {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private JedisClientPool jedisClientPool;
@Around("redisCacheAspect()")
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());
//得到被代理的方法上的注解
Object result = null;
//判断方法上是否有加入缓存的注解
if (method.isAnnotationPresent(RedisCache.class)){
String keyName = method.getAnnotation(RedisCache.class).keyName();
int cacheTime = method.getAnnotation(RedisCache.class).cacheTime();
if (keyName != null && !keyName.equals("")){
key = keyName+":"+key;
}
if(!jedisClientPool.exists(key)) {
logger.info("缓存未命中");
//缓存不存在,则调用原方法,并将结果放入缓存中
result = pjp.proceed(args);
redisResult = JSON.toJSONString(result);
if (cacheTime==-1){
jedisClientPool.set(key,redisResult);
}else {
jedisClientPool.set(key,redisResult,cacheTime);
}
} else{
//缓存命中
logger.info("缓存命中");
redisResult = jedisClientPool.get(key);
//得到被代理方法的返回值类型
Class returnType = method.getReturnType();
result = JSON.parseObject(redisResult,returnType);
}
}
//判断方法是否有删除缓存的注解
else if (method.isAnnotationPresent(RedisDel.class)){
result = pjp.proceed(args);
RedisDel redisDel = method.getAnnotation(RedisDel.class);
//是否删除所有
boolean all = redisDel.all();
String s = redisDel.keyName();
if (all){
Set keys = jedisClientPool.keys(s+"*");
for (String s1:keys){
jedisClientPool.del(s1);
}
}else {
jedisClientPool.del(s);
}
}else {
//执行方法。返回
result = pjp.proceed(args);
}
return result;
}
/**
* @Description: 生成key
* @Param:
* @return:
* @Author:
* @Date: 2018/5/16
*/
private String genKey(String className, String methodName, Object[] args) {
StringBuilder sb = new StringBuilder("");
sb.append(className);
sb.append(".");
sb.append(methodName);
for (Object object: args) {
logger.info("obj:"+object);
if(object!=null) {
sb.append("_");
sb.append(object+"");
}
}
return sb.toString();
}
}
RedisDel
注解,删除缓存
QQ群:552113611