Parsing spel expressions in Spring Aop

In Spring Aop, we can get the parameters of the interception method. If we can combine the spel expression, we can achieve more flexible functions. A typical implementation has Spring's cache annotation:

@Cacheable(value = "user", key = "#id", condition = "#id lt 10")
public User conditionFindById(final Long id) {
    
    
}

This article describes how to parse spel expressions in aop programming, and provides several common methods.

The way Spring uses custom annotations to implement aop will not be repeated here, only focusing on how to parse spel

The implementation is very simple, Spring itself provides a simple api, we only need to obtain:

Method: Method method
parameter: Object[] arguments
spel expression: String spel
These can be obtained from the parameter ProceedingJoinPoint of the aop entry method.
The spel expression is obviously obtained from the custom annotation, and the method and parameters are obtained as follows:

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. Get method parameter values

Object[] arguments = joinPoint.getArgs();

3. Analysis

private ExpressionParser parser = new SpelExpressionParser();


private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();

4. Analyze the parameters according to the spel expression and get the result

 /**
     * 解析 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;
        }
    }

to sum up

@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字符串,可能是 #{id},#{param.id}...
        // #{id} 参数中直接有id参数,#{param.id}表示从param对象的id属性中取值
        String spel = ...
        // 解析spel表达式
        Boolean result = parseSpel(method, arguments, spel, Boolean.class, Boolean.FALSE);
        // 业务操作,省略...
        ...
        return point.proceed();
    }
}

Guess you like

Origin blog.csdn.net/wujian_csdn_csdn/article/details/113122424