SpringAOP_構造注入實現

Lachlan_Yang發表於2021-05-06

SpringAOP_構造注入實現


AOP_面向切面程式設計初步瞭解

讓我們先想象一個場景,你正在編寫一個專案,在開發過程中的多個模組都有某段重複的程式碼,於是你選擇將其抽象成一個方法,然後在需要的地方呼叫這個方法,當需要修改這段程式碼時只需要修改這個方法就行。有一天,你的Boss給了新的需求,需要再抽象出一個方法,然後再在各個需要這個方法的模組呼叫這個方法,這可能就讓你頭疼了,需要修改大量的程式碼,於是會想,能不能不修改原始碼為系統業務新增某種功能呢?幸運的是,AOP可以很好的解決這個問題。

簡單介紹

AOP:保證開發者不修改原始碼的前提下,去為系統中的業務元件新增某種通用功能,本質是由AOP框架修改業務元件的多個方法的原始碼,我們將其分為兩類:

  • 靜態AOP
    AOP 框架在編譯階段對程式原始碼進行修改,生成了靜態的 AOP 代理類(生成的*.class檔案已經被改掉了,需要使用特定的編譯器),比如 AspectJ。
  • 動態AOP:
    AOP 框架在執行階段對動態生成代理物件(在記憶體中以 JDK 動態代理,或 CGlib 動態地生成 AOP 代理類),如 SpringAOP。

詳細說明

Spring 的通知型別

名稱 標籤 說明
前置通知 @Before 用於配置前置通知。指定增強的方法在切入點方法之前執行
後置通知 @AfterReturning 用於配置後置通知。指定增強的方法在切入點方法之後執行
環繞通知 @Around 用於配置環繞通知。指定增強的方法在切入點方法之前和之後都執行
異常通知 @AfterThrowing 用於配置異常丟擲通知。指定增強的方法在出現異常時執行
最終通知 @After 用於配置最終通知。無論增強方式執行是否有異常都會執行
切面類註解 @Aspect 標註該當前類是一個切面類
斷點註解 @Pointcut 使用一個返回值為 void 、方法體為空的方法來命名切入點

實戰演練

匯入依賴包

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.5</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.3.5</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.6</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>


建立一個增強類以及其介面

增強類介面:

public interface VisitService {
    //用於實現前置通知,後置通知,異常通知,最終通知
    void visit(String str) throws Exception;

    //用於實現環繞通知
    void around();
}

增強類:

public class VisitServiceImpl implements VisitService {
    //前置,後置,最終,異常通知的增強類
    public void visit(String str) throws Exception{
        System.out.println(str);
        if(!str.equalsIgnoreCase("agree")){
            throw new Exception("非法訪問");
        }
    }
    //環繞通知的增強類
    public void around() {
        System.out.println("環繞通知");
    }
}

建立一個切面類

@Component("VisitAspect")
@Aspect //標註當前myAspect是一個切面類
public class VisitAspect_anno {
    // 定義切入點表示式
    // 使用一個返回值為 void 、方法體為空的方法來命名切入點
    @Pointcut("execution(* Spring_AOP.service.impl.VisitServiceImpl.visit(..))")
    private void v1() {
    }

    //前置通知
    @Before("v1()")
    public void visitBefore(JoinPoint joinPoint) {

        System.out.println("口令:");
    }

    @After("v1()")
    //最終通知,無論是否報錯,都執行
    public void visitAfter(JoinPoint joinPoint) {
        System.out.println("輸入完成");
    }

    @AfterReturning("v1()")
    //後置通知報錯不執行
    public void visitSuccess(JoinPoint joinPoint) {
        System.out.println("請求成功,歡迎");
    }

    @AfterThrowing(value = "v1()",throwing = "ex")
    //異常通知,報錯後執行
    public void visitThrow(JoinPoint joinPoint, Throwable ex) {
        System.out.println("請求失敗,拒絕");
    }

    @Around("execution(* Spring_AOP.service.impl.VisitServiceImpl.around())")
    //環繞通知,如果報錯只執行前一句
    public Object visitAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("-------環繞-------");
        Object obj = proceedingJoinPoint.proceed();
        System.out.println("------------------");
        return obj;
    }
}


配置xml檔案

    <!-- 基於註解的宣告式 AspectJ -->
    <context:component-scan base-package="Spring_AOP" />
    <!-- 啟動基於註解的宣告式 AspectJ 支援一 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

建立一個測試類

 public class visitTest {
    @Test
    public void VisitTest(){
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext_AOP.xml");
        VisitService visitService = app.getBean(VisitService.class);
        try {
            visitService.visit("agree");
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            visitService.visit("ok");
        } catch (Exception e) {
            e.printStackTrace();
        }
        visitService.around();
    }
}

測試執行

口令:
agree
請求成功,歡迎
輸入完成
口令:
ok
請求失敗,拒絕
輸入完成
-------環繞-------
環繞通知
-------環繞-------


總結

  • 使用構造注入可以更方便的實現AOP模式,但是同樣與設定注入相比各有千秋。

以上就是以註解實現SpringAOP框架構造注入的實現,如有錯誤,麻煩指出,感謝耐心到現在的朋友ᕕ( ᐛ )ᕗ ---By 不斷努力的Yang

相關文章