面向切面(AOP)的理解和使用

是個什麼東西

面向對象,你們都聽過。那面向切面是個啥?面向切面是對面向對象的延伸。那就先從面向對象開始提及。java

縱向抽取

在面向對象中, 對重複的邏輯代碼會抽取出來,在須要用到的地方繼承便可。這就是縱向抽取git

橫向抽象

可是,縱向抽取需求並不能知足全部的抽取場景,好比在不一樣的方法有着一些重複的代碼邏輯,經過縱向抽取是沒辦法抽取使用的,代碼以下:github

主業務和系統業務耦合

因此咱們須要使用橫向切面的方式來對重複的邏輯代碼進行抽取複用,這就是面向切面編程:web

將分散在各個業務邏輯代碼中相同的代碼經過橫向切割的方式抽取到一個獨立的模塊中spring

image

在平常的開發中,代碼分爲主業務和系統級業務,上圖中的左側的就是主業務邏輯,右側就是系統級業務。系統級業務都應該用切面的方式抽取到獨立的模塊中,不和主業務代碼耦合,真正實現寫代碼時只需關注主業務的實現。編程

有哪些概念

相關概念bash

寫代碼實踐

經過定義一個權限檢查切面,來對全部的接口進行權限校驗。app

編寫兩個接口

一個添加接口,一個刪除接口,刪除接口須要userType爲admin纔有權限刪除。dom

@RestController
public class WebController {

    @GetMapping("add")
    public String add(@RequestParam("userType") String userType){
        System.out.println("add:添加用戶...");
        return "ok";
    }

    @GetMapping(value = "del")
    public String del(@RequestParam("userType") String userType){
        System.out.println("add:刪除用戶...");
        return "ok";
    }

}
複製代碼

編寫權限檢查AOP

定義切點

/**
     * 定義一個切點
     *
     * 經過匹配註解的方式切進來,全部被GetMapping 註解的方法都會經過這個切點進來
     *
     */
    @Pointcut(value = "@annotation(org.springframework.web.bind.annotation.GetMapping)")
    public void permissionCut(){}

複製代碼

實現切面邏輯

目標方法先後加強方法

@Around(value = "permissionCut()")
    public Object checkPermission(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("@Around:開始校驗權限...");
        Signature sig = joinPoint.getSignature();
        MethodSignature msig = null;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("該註解只能用於方法");
        }
        msig = (MethodSignature) sig;
        Method currentMethod = msig.getMethod();


        //獲取GetMapping註解中的路徑
        String methodMapping = null;
        GetMapping methodGetMapping = currentMethod.getAnnotation(GetMapping.class);
        if(methodGetMapping!=null&&methodGetMapping.value()!=null&&methodGetMapping.value().length>0) {
            methodMapping = methodGetMapping.value()[0];
        }

        //訪問目標方法的參數:
        String userType = "";
        Object[] args = joinPoint.getArgs();
        if (args != null && args.length > 0 && args[0].getClass() == String.class) {
            userType = (String) args[0];
        }

        //刪除接口須要驗證管理員權限
        if ("del".equals(methodMapping)){
            if (userType.equals("admin")) {
                //執行目標方法
                joinPoint.proceed();
                System.out.println("@Around:知足權限...");
                return "ok";
            }else {
                System.out.println("@Around:不知足權限...");
                return "無權限訪問";
            }
        }
            return joinPoint.proceed();

    }
複製代碼

其餘加強方法

@Before("permissionCut()")
    public void permissionCheck(JoinPoint point) {
        System.out.println("@Before:開始權限檢查...");
        System.out.println("@Before:目標方法爲:" +
                point.getSignature().getDeclaringTypeName() +
                "." + point.getSignature().getName());
        System.out.println("@Before:參數爲:" + Arrays.toString(point.getArgs()));
        System.out.println("@Before:被織入的目標對象爲:" + point.getTarget());
    }

    @AfterReturning(pointcut="permissionCut()",
            returning="returnValue")
    public void log(JoinPoint point, Object returnValue) {
        System.out.println("@AfterReturning:開始記錄返回值...");
        System.out.println("@AfterReturning:目標方法爲:" +
                point.getSignature().getDeclaringTypeName() +
                "." + point.getSignature().getName());
        System.out.println("@AfterReturning:參數爲:" +
                Arrays.toString(point.getArgs()));
        System.out.println("@AfterReturning:返回值爲:" + returnValue);
        System.out.println("@AfterReturning:被織入的目標對象爲:" + point.getTarget());

    }

    @After("permissionCut()")
    public void releaseResource(JoinPoint point) {
        System.out.println("@Before:結束權限檢查...");
    }
複製代碼

完整項目代碼

github.com/domain9065/…ui

相關文章
相關標籤/搜索