🌓 场景:
对于指定注解的方法进行Aop,同时需要支持SPEL表达式的解析
都是成熟的程序员了,就直接上代码了
🔥 代码:
自定义注解
/**
* @author cocowwy.cn
* @create 2022-05-05-11:45
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RefreshBranch {
String value();
}
切面逻辑
/**
* @author cocowwy.cn
* @create 2022-05-05-11:45
*/
@Aspect
@Component
public class AopRefreshBranch {
private final ExpressionParser parser = new SpelExpressionParser();
private final LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
// 切入点,切入指定的注解
@Pointcut("@annotation(refreshBranch)")
public void pointCut(RefreshBranch refreshBranch) {
}
// 切面,这里用的后置切面
@After("pointCut(refreshBranch)")
public void around(JoinPoint jp, RefreshBranch refreshBranch) {
// 得到切方法
Method method = this.getMethod(jp);
Object[] arguments = jp.getArgs();
// 解析spel表达式
String result = parseSpel(method, arguments, refreshBranch.value(), String.class, "");
// 自己的逻辑....
}
private Method getMethod(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
if (method.getDeclaringClass().isInterface()) {
try {
method = joinPoint
.getTarget()
.getClass()
.getDeclaredMethod(joinPoint.getSignature().getName(),
method.getParameterTypes());
} catch (SecurityException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
return method;
}
/**
* 解析 spel 表达式
*
* @param method 方法
* @param arguments 参数
* @param spel 表达式
* @param clazz 返回结果的类型
* @param defaultResult 默认结果
* @return 执行spel表达式后的结果
*/
private <T> T parseSpel(Method method, Object[] arguments, String spel, Class<T> clazz, T defaultResult) {
String[] params = discoverer.getParameterNames(method);
EvaluationContext context = new StandardEvaluationContext();
for (int len = 0; len < Objects.requireNonNull(params).length; len++) {
context.setVariable(params[len], arguments[len]);
}
try {
Expression expression = parser.parseExpression(spel);
return expression.getValue(context, clazz);
} catch (Exception e) {
return defaultResult;
}
}
}
切入方法
表示取参数的id值
@RefreshBranch(value = "#branch.id")
public void XXXXXXXX(@RequestBody XXXXX branch) {...}