предисловие
В Spring Aop мы можем получить параметры метода перехвата.Если мы сможем объединить выражение spel, мы сможем добиться более гибких функций. Типичная реализация имеет аннотации кэширования Spring:
@Cacheable(value = "user", key = "#id", condition = "#id lt 10")
public User conditionFindById(final Long id) {
}
@Caching(put = {
@CachePut(value = "user", key = "#user.id"),
@CachePut(value = "user", key = "#user.username"),
@CachePut(value = "user", key = "#user.email")
})
public User save(User user) {
В этой статье рассказывается, как анализировать spel-выражения в АОП-программировании, и приводятся несколько общих методов.
То, как Spring использует пользовательские аннотации для реализации aop, здесь не будет повторяться, а будет сосредоточено только на том, как анализировать spel.
Подготовить
Реализация очень простая, Spring сам предоставляет простой API, нам нужно только получить:
- метод:
Method method
- Параметры метода:
Object[] arguments
- орфографическое выражение:
String spel
Доступ к ним можно получить из параметров метода ввода aop.ProceedingJoinPoint
получено в.
Выражение spel очевидно получается из пользовательской аннотации, а метод и параметры получаются следующим образом:
Получить метод:
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;
}
Получить значения параметров метода:
Object[] arguments = joinPoint.getArgs();
Разобрать
Затем, чтобы проанализировать выражение spel, сначала определите два свойства в классе aop:
private ExpressionParser parser = new SpelExpressionParser();
private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
Разбираем параметры в соответствии с выражением spel и получаем результат:
/**
* 解析 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 < 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;
}
}
Суммировать
Выше приведен ключевой процесс разбора выражения spel.В целом структура класса aop выглядит следующим образом:
@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;
// 获取方法参数值
Object[] arguments = point.getArgs();
// 获取方法
Method method = getMethod(point);
// 从注解中获取spel字符串,省略...
String spel = ...
// 解析spel表达式
Boolean result = parseSpel(method, arguments, spel, Boolean.class, Boolean.FALSE);
// 业务操作,省略...
...
return point.proceed();
}
}
Вышеизложенное дает основную идею и несколько общих методов (#getMethod
,#parseSpel
), то всем пора фантазировать!