基於註解的切面編程

1.基本概念java

    面向切面編程也叫Aop。面向對象的特色是繼承、封裝、多態。封裝要求咱們將不一樣的功能分散到不一樣的類中去實現,每一個類有本身的職責,這樣的好處是下降了代碼的複雜度,使得類能夠重用;可是在分散代碼的同時,也會增長代碼的複雜性,好比一些通用的功能,日誌,權限等。在以前進行app後端開發的時候,爲了跟蹤問題,須要對每一個api的請求日誌都記錄下來,能夠在每一個方法的入口處都加上log.info.....,可是這樣不夠靈活,若是之後對記錄的日誌的方式變化,那麼改動可想而知,也許你會說封裝起來,每一個類中進行調用,可是這樣就耦合太嚴重了。這時候就可使用Aop,在運行時動態的插入代碼;這種在運行時,動態地將代碼切入到類的指定方法、指定位置上的編程思想就是面向切面的編程。web

    通常而言,咱們將切入到指定類指定方法的代碼片斷稱爲切面,將切入到哪些類,或者哪些方法的稱爲切入點。使用Aop,將不一樣類中重複的地方抽取出來,造成切面,在須要的地方插入到對象或方法上,從而動態改變原有的行爲。spring

2.一個簡單權限校驗的例子編程

基於註解的切面,須要定義註解,定義切面後端

1>定義註解api

package com.example.springbootDemo.service.aspect;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE,ElementType.METHOD})//註解類型,級別
@Retention(RetentionPolicy.RUNTIME)//運行時註解
public @interface PermissionCheck {
    String value() default "";
}

2>根據註解定義一個切面springboot

package com.example.springbootDemo.service.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class PermissionAspect {
    /**
     * 選取切入點爲自定義註解
     */
    @Pointcut("@annotation(com.example.springbootDemo.service.aspect.PermissionCheck)")
    public void permissionCheck(){}

    /**
     * 在切入點業務邏輯執行前進行操做
     * @param joinPoint
     */
    @Before(value = "permissionCheck();")
    public void before(JoinPoint joinPoint) throws Throwable {
        Signature signature = joinPoint.getSignature(); //獲取鏈接點的方法簽名對象
        if (!(signature instanceof MethodSignature)){
            throw new PermissionCheckException("user permission check fail,stop this request!");
        }
        MethodSignature methodSignature = (MethodSignature) signature;
        Object target = joinPoint.getTarget();
        Method method = target.getClass().getDeclaredMethod(methodSignature.getName(),methodSignature.getParameterTypes());//獲取到當前執行的方法
        PermissionCheck annotation = method.getAnnotation(PermissionCheck.class);//獲取方法的註解
        System.out.println(annotation);
        System.out.println(annotation.value());
        System.out.println("我是在執行業務邏輯以前");
    }

    /**
     * 在業務邏輯執行後進行的操做
     * @param joinPoint
     */
    @After(value = "permissionCheck();")
    public void after(JoinPoint joinPoint) throws NoSuchMethodException {
        System.out.println("我是在執行業務邏輯後");
    }

    @Around(value = "permissionCheck();")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("around方法執行前1");
        Object proceed = joinPoint.proceed();
        System.out.println("around方法執行前2");
        System.out.println("proceed:"+proceed.toString());
        return proceed;
    }
}

3>權限驗證不知足的時候須要定義異常,定義一個PermissionCheckException來標識權限不知足的異常信息app

package com.example.springbootDemo.service.aspect;

public class PermissionCheckException extends RuntimeException {
    public PermissionCheckException(String message) {
        super(message);
    }
}

4>定義Advice處理該異常this

package com.example.springbootDemo.service.aspect;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

@ControllerAdvice
public class PermissionAdvice {
    @ExceptionHandler(value = PermissionCheckException.class)
    @ResponseStatus(value = HttpStatus.OK)
    @ResponseBody
    public String dealWithPermissionCheckException(PermissionCheckException exception){
        System.out.println(exception.getMessage());
        return exception.getMessage();
    }
}

注:PermissionCheck 註解必須聲明爲@Retention(RetentionPolicy.RUNTIME),不然,默認的是@Retention(RetentionPolicy.CLASS) 註解會在class字節碼文件中存在,但運行時沒法得到;.net

3.@Before @Around @After 等 advice 的執行順序

正常狀況的執行順序

異常狀況

注:Around中

Object proceed = joinPoint.proceed();

表示

Proceed with the next advice or target method invocation

表示處理返回的結果對象,必須返回;

相關文章
相關標籤/搜索