Spring AOP自定義Annotation(註解)記錄日誌

   什麼是AOP?web

    它利用一種稱爲"橫切"的技術,剖解開封裝的對象內部,並將那些影響了多個類的公共行爲封裝到一個可重用模塊,並將其命名爲"Aspect",即切面。所謂"切面",簡單說就是那些與業務無關,卻爲業務模塊所共同調用的邏輯或責任封裝起來,便於減小系統的重複代碼,下降模塊之間的耦合度,並有利於將來的可操做性和可維護性。若是說面向對象編程(oop)是水平擴展的話,那麼aop則是縱向的擴展,使程序立體化。數據庫

   定義一個註解編程

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Loggable {
    /** 操做類型(INSERT、UPDATE、SELECT、DELETE)*/
    public String optType();
    /** 描述 */
    public String describe();
    /** 模塊 */
    public String module();

   自定義註解app

@Retention:標示註解在何時可見(運行時可見、僅在.class文件及源代碼中可見、僅在源代碼中可見),value可用參數有:
  RetentionPolicy.RUNTIME    標示該註解能夠再運行時經過反射找到(ORM框架許多註解使用了該參數)
  RetentionPolicy.CLASS    標示該註解保存在.class文件中,但在運行時不能經過反射找到
  RetentionPolicy.SOURSE    標示該註解只在源碼中可見

@Target:標示該註解用於註解什麼元素(類、方法、變量等),value可用參數有:
  ElementType.PACKAGE    標示該註解用於註解包聲明
  ElementType.ANNOTATION_TYPE    標示該註解用於註解其餘註解
  ElementType.CONSTRUCTOR    標示該註解用於註解構造函數
  ElementType.FIELD    標示該註解用於註解成員變量
  ElementType.METHOD    標示該註解用於註解方法
  ElementType.TYPE    標示該註解用於註解類,接口,枚舉類型
  ElementType.PARAMETER    標示該註解用於註解參數
  ElementType.LOCAL_VARIABLE    標示該註解用於註解局部變量

   定義一個切面類(根據項目狀況在裏面科將日誌記錄存到數據庫):框架

@Aspect
@Component(value = "loggerAspect")
public class LoggerAspect {
    private Logger logger = LoggerFactory.getLogger(LoggerAspect.class);
    //切入點:* com.wb.wbao.web.*.*(..)路徑下和使用了@Loggable註解的方法
    @Pointcut("execution(public * com.wb.wbao.web.*.*(..)) && @annotation(com.wb.wbao.common.annotation.Loggable)")
    public void log(){
    }
    @AfterReturning(value = "log()", returning = "retVal")
    public void log(JoinPoint joinPoint, Object retVal) {
        // 獲取參數
        Object[] params = joinPoint.getArgs();
        // 獲取方法名
        String methodName = joinPoint.getSignature().getName();
        Class<?> targetClass = joinPoint.getTarget().getClass();
        Method method = null;
        for (Method mt : targetClass.getMethods()) {
            if (methodName.equals(mt.getName())) {
                method = mt;
                break;
            }
        }
        Loggable loggable = method.getAnnotation(Loggable.class);
        if(Objects.isNull(loggable)){
            return;
        }
        logger.info("loggable desc:{}, optType:{}, module:{},params:{}", loggable.describe(), loggable.optType(), loggable.module(), params);
        //loggable desc:登陸, optType:POST, module:LOGIN,params:[User{loginName='wangbao', password='wangbao'}
    }
 
    @AfterThrowing(value = "log()", throwing = "ex")
    public void log(JoinPoint joinPoint, Throwable ex) {
        // 獲取參數
        Object[] params = joinPoint.getArgs();
        // 獲取方法名
        String methodName = joinPoint.getSignature().getName();
        Class<?> targetClass = joinPoint.getTarget().getClass();
        Method method = null;
        for (Method mt : targetClass.getMethods()) {
            if (methodName.equals(mt.getName())) {
                method = mt;
                break;
            }
        }
        Loggable loggable = method.getAnnotation(Loggable.class);
        if(Objects.isNull(loggable)){
            return;
        }
        logger.info("loggable desc:{}, optType:{}, module:{}, exception:{}, params:{}", loggable.describe(), loggable.optType(), loggable.module(), ex.getMessage(),  params);
        //loggable desc:登陸, optType:POST, module:LOGIN, exception:/ by zero, params:[User{loginName='wangbao', password='wangbao'}
    }
}

   實際使用方法:函數

@Loggable(describe = "登陸", optType = "POST", module = "LOGIN")
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    @ResponseBody
     public CommonDTO login(@RequestBody User user) {...}
相關文章
相關標籤/搜索