springCloud使用自定义注解实现redis缓存
每次使用redis缓存的时候,都要去写redisTemplate相关的代码,第一步先去redis中读数据,有数据就解析并返回。 第二步,如果没有数据,再去调用本地方法读取数据。 第三步,将数据放到redis中。
这就是模板模式的套路,除了redis的key、缓存时间和数据类型不同外,其他的流程都是一样的。如果抽象成模板模式,会省事很多。 如果用自定义注解来实现,则用起来会很爽,每次在目标方法上加个注解,指定一下redis相关的参数就可以了
首先实现自定义注解:
```java
package com.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisCache {
String redisKey() ;
String timeOut(); //超时时间, 单位TimeUnit.MILLISECONDS
String resultObjClass(); //返回数据类型
String isList() default "false"; //返回数据是否是List
}
定义切点和切面,实现缓存逻辑
```java
package com.annotation;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import org.aspectj.lang.ProceedingJoinPoint;
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.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.TimeUnit;
@Aspect
@Component
public class RedisCacheAspect {
private static final Logger logger = LoggerFactory.getLogger(RedisCacheAspect.class);
@Autowired
private StringRedisTemplate stringRedisTemplate; //注入redis模板
@Pointcut("@annotation(com.annotation.RedisCache)") //定义切点
public void redisCachePointCut() {
}
@Around("redisCachePointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
RedisCache redisCache = method.getAnnotation(RedisCache.class);
try {
if (redisCache != null) {
// 注解上的描述
Gson gson = new Gson();
String redisKey = redisCache.redisKey();
Integer timeOut = Integer.parseInt(redisCache.timeOut());
String resultObj = redisCache.resultObjClass();
boolean isList = Boolean.parseBoolean(redisCache.isList());
String realValue = stringRedisTemplate.opsForValue().get(redisKey); //获取redis数据
if (!StringUtils.isEmpty(realValue)) {
logger.info("redisValue:{}", realValue);
Class resultObjClass = Class.forName(resultObj);
if (isList) {//如果是list类型的返回数据
JsonParser jsonParser = new JsonParser();
JsonArray jsonArray = jsonParser.parse(realValue).getAsJsonArray();
List resultList = new ArrayList();
if (jsonArray != null) {
for (JsonElement element : jsonArray) {
resultList.add(gson.fromJson(element, resultObjClass));
}
}
return resultList;
}
return gson.fromJson(realValue, resultObjClass);
} else {
Object result = point.proceed();
realValue = new Gson().toJson(result);
stringRedisTemplate.opsForValue().set(redisKey, realValue, timeOut, TimeUnit.MILLISECONDS);
return result;
}
}
}catch (Exception e){
logger.error("redisCachePointCutError!", e);
return point.proceed(); //异常直接执行方法
}
return null;
}
}
测试代码,测试不同的数据类型,解析是否支持。
package com.controller;
import com.bo.TestObj;
import com.service.FirstService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class FirstController {
@Autowired
private FirstService firstService;
@GetMapping("/hi")
public String firstMethod(@RequestParam String param){
return firstService.f(param);
}
@GetMapping("/hi2")
public TestObj firstMethod2(@RequestParam String param){
return firstService.g(param);
}
@GetMapping("/hi3")
public Integer firstMethod3(@RequestParam Integer param){
return firstService.i(param);
}
@GetMapping("/hi4")
public List<String> firstMethod4(@RequestParam String param){
return firstService.j(param);
}
@GetMapping("/hi5")
public List<Integer> firstMethod4(@RequestParam Integer param){
return firstService.k(param);
}
@GetMapping("/hi6")
public List<TestObj> firstMethod5(@RequestParam Integer param){
return firstService.l(param);
}
}
service:
package com.service;
import com.annotation.RedisCache;
import com.bo.TestObj;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
@Service
public class FirstService {
@RedisCache(timeOut = "5000", redisKey = "redis_prefix", resultObjClass = "java.lang.String")
public String f(String param){
return "hello ni hao :"+param;
}
@RedisCache(timeOut = "5000", redisKey = "redis_prefix2", resultObjClass = "com.bo.TestObj")
public TestObj g(String param){
TestObj testObj = new TestObj();
testObj.setName("name:"+param);
testObj.setDesc("desc:"+param);
return testObj;
}
@RedisCache(timeOut = "5000", redisKey = "redis_prefix3", resultObjClass = "java.lang.Integer")
public Integer i(Integer param){
return 2*param;
}
@RedisCache(timeOut = "5000", redisKey = "redis_prefix4", resultObjClass = "java.lang.String", isList="true")
public List<String> j(String param){
return Arrays.asList("1,","2", param);
}
@RedisCache(timeOut = "5000", redisKey = "redis_prefix5", resultObjClass = "java.lang.Integer", isList="true")
public List<Integer> k(Integer param){
return Arrays.asList(1,2, param);
}
@RedisCache(timeOut = "5000", redisKey = "redis_prefix6", resultObjClass = "com.bo.TestObj", isList="true")
public List<TestObj> l(Integer param){
TestObj testObj1= new TestObj();
TestObj testObj2= new TestObj();
testObj1.setName("1name"+param);
testObj2.setName("2name"+param);
testObj1.setDesc("1desc"+param);
testObj2.setDesc("2desc"+param);
return Arrays.asList(testObj1, testObj2);
}
}
appliation.yml:
spring:
application:
name: first_controller
redis:
database: 10
host: 1*2.26.***.3
port: 8001
password: ******