Spring AOP动态获取函数参数中的值

一个简单的栗子,我们需要记录一个订单系统的订单状态流转日志。为了符合开闭原则,我们只能新加代码,随之引入AOP。AOP的引入是这个功能实现的基础。接着AOP的作用域是我们要思考的。最方便直观的当然是注解。所以我们要自定义一个注解。作用于需要记录日志的方法上。然后,问题又来了,不通的函数,可能接口参数并不一致。我们并不能直接获取到我们关心的订单数据。但是根据我的经验,通常这些接口参数都会包含最能说明=订单数据的订单号存在。为了能够解析这个订单号,我们需要引入Spring中的SpelExpressionParser来从参数中解析出订单号。

1.注解

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface OpLogger {
    /**
     * 特殊处理类
     * @return
     */
    Class<?> handleClass() default Class.class;
    /**
     * 特殊处理的函数名,默认不处理
     * @return
     */
    String method() default "";

    /**
     * 参数字段
     * @return
     */
    String value() default "#orderNo";

    /**
     * 备注信息
     * @return
     */
    String remark() default "";

    /**
     * 参数处理类
     * @return
     */
    Class<?> paramsClass() default Class.class;

    /**
     * 参数处理方法
     * @return
     */
    String paramsMethod() default "";
}

 

2.参数解析工具类

public static <T> T parseExpression(String expression, Method method, Object[] args, Class<T> classType) {
        if (StringUtils.isBlank(expression)) {
            return null;
        } else if (!expression.trim().startsWith("#") && !expression.trim().startsWith("$")) {
            return null;
        } else {
            LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
            String[] paramNames = discoverer.getParameterNames(method);
            if (ArrayUtils.isEmpty(paramNames)) {
                return null;
            } else {
                StandardEvaluationContext context = new StandardEvaluationContext();

                for (int i = 0; i < paramNames.length; ++i) {
                    context.setVariable(paramNames[i], args[i]);
                }
                return (new SpelExpressionParser()).parseExpression(expression).getValue(context, classType);
            }
        }
    }

3.AOP

 @Pointcut("@annotation(logger)")
 public void cutPoint(OpLogger logger) {}

此后就是自己的业务处理逻辑,不管是使用@Around,还是@Before、@After都能做到记录完整日志。

 

关于注解的使用,需要AOP中来配合

@OpLogger(value = "#mess",paramsClass = ParamsHelper.class,paramsMethod = "getAppCode")
这个意思表明获得参数中mess的值,通过参数处理类ParamsHelper中的getAppCode方法从mess对象中拿到订单号。
@OpLogger(value = "#userInfo[appCode]",handleClass = OrderInfoHelper.class,method = "buildOrder")
这个意思表明从Map userInfo中拿到appCode属性,这个就是订单号了,处理过程中设计到的一些特殊处理逻辑使用OrderInfoHelper类中的buildOrder来处理

获取订单号直接调用工具类将注解中的value值传入即可。

2018-11-07 记
posted @ 2018-11-07 11:55  田野里的放牛娃  阅读(3976)  评论(0编辑  收藏  举报