基於schema的AOP,實現日誌記錄Demo

筆者今天使用<aop:aspect>配置文件的形式,外加註解,一個接口,一個日誌記錄類,實現訪問某些指定Controller層方法時候記錄日誌的功能,並在註解中傳入參數functionCode和menuCode,供日誌記錄類使用,

如下爲Demo代碼:

1.準備工作,一個註解的接口類

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/*
 * 業務日誌接口
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface SaveLog {
    
    //接口成員:基本以及衍生的數據類型  無入參 無異常
    String menuCode();
    String functionCode();
}
說明:SaveLog接口必須使用@標註,可解釋爲標籤;接口的參數成員menuCode,functionCode必須是無參的,且是八種基本數據類型及其衍生類;如List menu(),就是錯誤的。

2.Controller裏的調用方法

/**
     * 
     *  
     * 〈日誌記錄Demo入口〉
     *
     * @return
     * @see [相關類/方法](可選)
     * @since [產品/模塊版本](可選)
     */
    @ResponseBody
    @RequestMapping("/aopTest.action")
    @SaveLog(menuCode="10",functionCode="20")
    public Map<String, Object> aopTest(String a){
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("aopTest", "true");
        return map;
    }

說明:這裏請重點關注@SaveLog,並且傳入參數menuCode="10"和functionCode="20",aopTest(String a)方法傳入參數String a,返回一個Map對象,這些參數打算在日誌記錄裏捕獲。

3.Spring裏的配置文件




<!--  logSave切面配置 -->
	<aop:config proxy-target-class="true">
		<aop:aspect ref="SaveLog">
			<aop:pointcut expression="execution(* com.suning.sample.web.*.*(..))" 
				id="SaveLogPoint"/>
			<aop:after-returning method="saveBusinessLog" 
				pointcut-ref="SaveLogPoint"  returning="res"/>
		</aop:aspect>
	</aop:config>
	<bean id="SaveLog" class="com.suning.schema.aop.SaveLogImpl"></bean>

說明:proxy-target-class="true"是指使用CGLIB的動態代理,定義一個切面SaveLog指的是SaveLogImpl這個類,切點是com.suning.sample.web包下所有類的所有方法,第一個*是指返回值任意,第二個*指com.suning.sample.web包下任意類,第三個*指任意方法,(..)指方法參數任意;在切入點上的方法執行結束後(after-return),調用切面SaveLog的saveBusinessLog()方法,並傳入參數res:


4.重點:此處爲實現記錄業務日誌的關鍵類SaveLogImpl.java

package com.suning.schema.aop;

import java.lang.reflect.Method;
import java.util.Map;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;


/*
 * 切面增強實現類
 */
public class SaveLogImpl{
    
    public void saveBusinessLog(JoinPoint joinPoint, Map<String,Object> res){
        // 得到類路徑
        String classType = joinPoint.getTarget().getClass().getName();
        // 得到方法名
        String methodName = joinPoint.getSignature().getName();
        MethodSignature jp = (MethodSignature) joinPoint.getSignature();
        Method method = jp.getMethod();
        Class<?>[] parameterTypes = method.getParameterTypes();
        Class<?> className = null;
        try {
            className = Class.forName(classType);
            method = className.getMethod(methodName, parameterTypes);
        }catch(Exception e){
            System.out.println("拋異常");
        } 
        SaveLog desc = method.getAnnotation(SaveLog.class);
        System.out.println("SaveLog註解參數functionCode:" + desc.functionCode());
        System.out.println("SaveLog註解參數menuCode:" + desc.menuCode());
    }
}

說明:我的demo裏重點是展現獲取連接點相關的參數,包括如下三個參數



還記得配置文件中這個麼?


其實他是aopTest作爲參數傳給了saveBusinessLog這個記錄日誌的業務方法,如下:





5:測試,地址欄中輸入如下地址,地址中傳入參數a=1




查看saveBusinessLog()方法是否獲取了連接點的相關值:




心得:同一pointCut下的增強方法均會執行,小技巧就是在配置文件中最好細化切入點。不贅述。







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章