在Spring Aop中,我們可以拿到攔截方法的參數(shù),如果能結(jié)合spel表達式峦剔,就能實現(xiàn)更加靈活的功能。典型的實現(xiàn)有Spring的緩存注解:
@Cacheable(value = "user", key = "#id", condition = "#id lt 10")
public User conditionFindById(final Long id) {
}
本文介紹如何在aop編程中解析spel表達式角钩,提供幾個通用的方法吝沫。
Spring使用自定義注解實現(xiàn)aop的方式這里就不贅述,只著重介紹如何解析spel
實現(xiàn)非常簡單递礼,Spring本身就提供了簡便的api惨险,我們只需要獲取:
- 方法:Method method
- 方法參數(shù):Object[] arguments
- spel表達式:String spel
這些都能從aop入口方法的參數(shù)ProceedingJoinPoint中得到脊髓。
spel表達式顯然就是從自定義注解中獲取了辫愉,而獲取方法和參數(shù)的方式如下:
1、獲取方法
private Method getMethod(ProceedingJoinPoint 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;
}
2将硝、獲取方法參數(shù)值
Object[] arguments = joinPoint.getArgs();
3恭朗、解析
private ExpressionParser parser = new SpelExpressionParser();
private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
4、根據(jù)spel表達式解析參數(shù)依疼,得到結(jié)果
/**
* 解析 spel 表達式
*
* @param method 方法
* @param arguments 參數(shù)
* @param spel 表達式
* @param clazz 返回結(jié)果的類型
* @param defaultResult 默認(rèn)結(jié)果
* @return 執(zhí)行spel表達式后的結(jié)果
*/
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 < 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;
}
}
總結(jié)
@Aspect
public class SpelAspect {
private ExpressionParser parser = new SpelExpressionParser();
private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
@Around(value = "@annotation(自定義注解)")
public Object test(ProceedingJoinPoint point) throws Throwable {
Object obj;
// 獲取方法參數(shù)值
Object[] arguments = point.getArgs();
// 獲取方法
Method method = getMethod(point);
// 從注解中獲取spel字符串痰腮,省略...
String spel = ...
// 解析spel表達式
Boolean result = parseSpel(method, arguments, spel, Boolean.class, Boolean.FALSE);
// 業(yè)務(wù)操作,省略...
...
return point.proceed();
}
}