學習了自定義緩存註解,在這裏做下記錄
以下代碼簡單的實現了一個緩存的流程:查詢數據時先查詢redis緩存,緩存中沒有就去Mysql中取出並緩存到redis中。
這次要替代一個以前從來沒遇到過的點,就是spring的EL表達式的解析
/**
* 使用SPEL進行key的解析
*
* @param expressionString 表達式字符串
* @param method 方法對象,用於獲取參數名
* @param args 方法的參數值
* @return
*/
private String parseExpression(String expressionString, Method method, Object[] args) {
//獲取被攔截方法參數名列表
LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
String[] paramNameArr = discoverer.getParameterNames(method);
//SPEL解析
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
for (int i = 0; i < paramNameArr.length; i++) {
context.setVariable(paramNameArr[i], args[i]);
}
String result = parser.parseExpression(expressionString).getValue(context, String.class);
return result;
}
基於spring註解切面實現的redis切面緩存
import com.annotation.MyAnnotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.DefaultParameterNameDiscoverer;
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;
@Aspect
@Component
public class MyAnnotationAspect {
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Around("@annotation(com.annotation.MyAnnotation)")
public Object MyAnnotation(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("進入註解片面~~~~~~~~");
//疑問key的內容-根據方法參數1,獲取到方法註解裏面的key內容-反射知識
MethodSignature signature = (MethodSignature) proceedingJoinPoint. getSignature();
Method method = proceedingJoinPoint.getTarget().getClass().getMethod(signature.getName(),signature.getMethod().getParameterTypes());
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
//反射技術-JDK最底層的API
String keyEL = myAnnotation.key();
System.out.println("註解中key的值keyEL:"+keyEL);
// 2.拿到方法的參數名和參數值, 方便解析key表達式
// 創建解析器
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser. parseExpression (keyEL);
//設置解析上下文(有哪些佔位荷,以及每種佔位符的值-根據方法的參數名和參數值
EvaluationContext context = new StandardEvaluationContext();
//參歌
Object [] args = proceedingJoinPoint. getArgs();
String [] parameterNames=new DefaultParameterNameDiscoverer().getParameterNames(method);
for (int i =0; i < parameterNames.length; i++){
System.out.println("參數名:"+ parameterNames[i]+"; 參數值:"+args[i]);
context.setVariable(parameterNames[i],args[i]);
}
// T0D0 3,解析表達式,生成最終的key
String key = expression.getValue(context).toString();
//1 redis緩存一性能需求-查詢併發量
System.out.println("緩存中有數據: "+key);
Object o = redisTemplate.opsForValue().get(key);
if (o != null){
//緩存中有數據直接返回數據
return o;
}
Object proceed = proceedingJoinPoint.proceed();
if (proceed != null){
//緩存數據
redisTemplate.opsForValue().set(key,proceed);
}
System.out.println("結束註解片面~~~~~~~~");
return proceed;
}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String key();
}
@MyAnnotationAspect(key = "#argid")
@Override
public Object testAnnotation(String argid,String arg01){
System.out.println("testAnnotation: argid="+argid+"; arg01="+arg01);
AdminUser byname = null;
AdminUser byname = adminUserMapper.findByname(argid);
return byname;
}