Spring Cloud Alibaba-AOP(十九)

簡介

AOP(面向切面編程),做爲OOP(面向對象編程)的補充,用於處理哪些業務無關的,例如鑑權,日誌等公共邏輯,將之抽取封裝成一個可重用的模塊(切面),減小代碼重複,下降耦合,提升系統可維護性。java

方式

靜態代理

編譯階段將AspectJ(切面)織入到Java字節碼生成AOP代理類spring

動態代理

運行階段在內存中臨時生產一個AOP對象且在特定的切點作了加強處理編程

  • JDK動態代理(基於接口)
  • CGLIB動態代理(基於繼承)

術語

  • Advice(通知/加強):切面須要作的具體工做
  • Join point(鏈接點):容許使用通知的地方
  • Poincut(切點):執行的位置
  • Aspect(切面):通知和切點的結合
  • Introduction(引入):切面定義的屬性方法應用到目標類
  • target(目標):被通知的對象
  • Weaving(織入):把切面加入程序代碼的過程

經常使用的加強類型

  • 前置通知(before):在某鏈接點以前執行的通知,但這個通知不能阻止鏈接點前的執行(除非拋出異常)
  • 返回後通知(afterReturning):在某鏈接點正常完成後執行的通知
  • 拋出異常後通知(afterThrowing):在方法拋出異常退出時執行的通知
  • 後通知(after):當某鏈接點退出的時候執行的通知
  • 環繞通知(around):包圍一個鏈接點通知

執行順序

  • @Order(1):越小越先執行
  • around->before->around->after->afterReturning
  • 橙色:@Order(1),綠色:@Order(2)

Springboot引入AOP

  • 加依賴
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
複製代碼
  • 寫註解
複製代碼
  • 寫配置
複製代碼

Introduction

package com.virgo.user.auto;

import com.virgo.user.service.TestService;
import com.virgo.user.service.TestServiceImpl;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.stereotype.Component;

/**
 * @author zhaozha
 * @date 2019/10/24 下午1:00
 */
@Aspect
@Component
public class IntroductionAop {
    @DeclareParents(value = "com.virgo.user..service..*", defaultImpl = TestServiceImpl.class)
    public TestService testService;
}

package com.virgo.user.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * @author zhaozha
 * @date 2019/10/24 下午1:02
 */
@Service
@Slf4j
public class TestServiceImpl implements TestService{
    @Override
    public void test() {
        log.info("all can use");
    }
}


...
        // CommonService使用TestService
        TestService testService = (TestService)commonServiceImpl;
        testService.test();
...
複製代碼

順序

  • 代碼
package com.virgo.user.auto;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author zhaozha
 * @date 2019/10/24 下午1:29
 */
@Slf4j
@Aspect
@Component
@Order(1)
public class TestAopOrder1 {
    @Pointcut("execution(* com.virgo.user.service.*.*(..))")
    public void pointcut() {
    }

    @Before("pointcut()")
    public void begin() {
        log.info("2:{}","before");
    }

    @After("pointcut()")
    public void commit() {
        log.info("9:{}","after");
    }

    @AfterReturning("pointcut()")
    public void afterReturning(JoinPoint joinPoint) {
        log.info("10:{}","afterReturning");
    }

    @AfterThrowing("pointcut()")
    public void afterThrowing() {
        log.info("afterThrowing");
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            log.info("1:{}","around");
            return joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
            throw e;
        } finally {
            log.info("8:{}","around");
        }
    }
}
package com.virgo.user.auto;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author zhaozha
 * @date 2019/10/24 下午1:11
 */
@Slf4j
@Aspect
@Component
@Order(2)
public class TestAopOrder2 {
    @Pointcut("execution(* com.virgo.user.service.*.*(..))")
    public void pointcut() {
    }

    @Before("pointcut()")
    public void begin() {
        log.info("4:{}","before");
    }

    @After("pointcut()")
    public void commit() {
        log.info("6:{}","after");
    }

    @AfterReturning("pointcut()")
    public void afterReturning(JoinPoint joinPoint) {
        log.info("7:{}","afterReturning");
    }

    @AfterThrowing("pointcut()")
    public void afterThrowing() {
        log.info("afterThrowing");
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            log.info("3:{}","around");
            return joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
            throw e;
        } finally {
            log.info("5:{}","around");
        }
    }
}
複製代碼
  • 效果

註解生效AOP

註解

  • @Target:註解的做用目標
    • ElementType.TYPE:容許被修飾的註解做用在類、接口和枚舉上
    • ElementType.FIELD:容許做用在屬性字段上
    • ElementType.METHOD:容許做用在方法上
    • ElementType.PARAMETER:容許做用在方法參數上
    • ElementType.CONSTRUCTOR:容許做用在構造器上
    • ElementType.LOCAL_VARIABLE:容許做用在本地局部變量上
    • ElementType.ANNOTATION_TYPE:容許做用在註解上
    • ElementType.PACKAGE:容許做用在包上
  • @Retention:註解的生命週期
    • RetentionPolicy.SOURCE:Annotations are to be discarded by the compiler.(編譯期可見,不會寫入 class 文件)
    • RetentionPolicy.CLASS:Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time. This is the default behavior.(寫入 class 文件,類加載丟棄)
    • RetentionPolicy.RUNTIME:Annotations are to be recorded in the class file by the compiler and retained by the VM at run time, so they may be read reflectively.(永久保存,能夠反射獲取)
  • @Documented:註解是否應當被包含在 JavaDoc 文檔中
  • @Inherited:是否容許子類繼承該註解

AOP

  • 代碼
package com.virgo.user.auto;

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

/**
 * @author zhaozha
 * @date 2019/10/24 下午1:39
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogAop {
    String value() default "";
}

package com.virgo.user.auto;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author zhaozha
 * @date 2019/10/24 下午1:53
 */
@Slf4j
@Aspect
@Component
@Order(1)
public class TestAnnotationAop {
    @Pointcut(value = "@annotation(logAop)", argNames = "logAop")
    public void pointcut(LogAop logAop) {
    }

    @Around(value = "pointcut(logAop)", argNames = "joinPoint,logAop")
    public Object around(ProceedingJoinPoint joinPoint,LogAop logAop) throws Throwable {
        try {
            log.info(logAop.value());
            return joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
            throw e;
        } finally {
            log.info("");
        }
    }
}
複製代碼
  • 效果(方法加註釋@LogAop("測試Annotation"))

execution

execution(* com.virgo.user.service...(..))bash

  • 第一個*:任意的返回值
  • com.virgo.user.service:包名
  • .. :當前包及其子包
  • *:全部類
  • .*(..) 表示任何方法,括號表明參數 .. 表示任意參數
相關文章
相關標籤/搜索