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 記


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM