Spring Aop原理及實現

一、AOP的基本概念:

  1. 什麼是aop:

AOP(Aspect Oriented Programming)稱爲面向切面編程,在程序開發中主要用來解決一些系統層面上的問題,比如日誌,事務,權限等待,Struts2的攔截器設計就是基於AOP的思想,是個比較經典的例子。
在不改變原有的邏輯的基礎上,增加一些額外的功能。代理也是這個功能,讀寫分離也能用aop來做。

AOP可以說是OOP(Object Oriented Programming,面向對象編程)的補充和完善。OOP引入封裝、繼承、多態等概念來建立一種對象層次結構,用於模擬公共行爲的一個集合。不過OOP允許開發者定義縱向的關係,但並不適合定義橫向的關係,例如日誌功能。日誌代碼往往橫向地散佈在所有對象層次中,而與它對應的對象的核心功能毫無關係對於其他類型的代碼,如安全性、異常處理和透明的持續性也都是如此,這種散佈在各處的無關的代碼被稱爲橫切(cross cutting),在OOP設計中,它導致了大量代碼的重複,而不利於各個模塊的重用。

AOP技術恰恰相反,它利用一種稱爲"橫切"的技術,剖解開封裝的對象內部,並將那些影響了多個類的公共行爲封裝到一個可重用模塊,並將其命名爲"Aspect",即切面。所謂"切面",簡單說就是那些與業務無關,卻爲業務模塊所共同調用的邏輯或責任封裝起來,便於減少系統的重複代碼,降低模塊之間的耦合度,並有利於未來的可操作性和可維護性。
使用"橫切"技術,AOP把軟件系統分爲兩個部分:核心關注點和橫切關注點。業務處理的主要流程是核心關注點,與之關係不大的部分是橫切關注點。橫切關注點的一個特點是,他們經常發生在覈心關注點的多處,而各處基本相似,比如權限認證、日誌、事物。AOP的作用在於分離系統中的各種關注點,將核心關注點和橫切關注點分離開來。

  1. AOP的相關概念:

(1)橫切關注點:對哪些方法進行攔截,攔截後怎麼處理,這些關注點稱之爲橫切關注點
(2)Aspect(切面):通常是一個類,裏面可以定義切入點和通知
(3)JointPoint(連接點):程序執行過程中明確的點,一般是方法的調用。被攔截到的點,因爲Spring只支持方法類型的連接點,所以在Spring中連接點指的就是被攔截到的方法,實際上連接點還可以是字段或者構造器
(4)Advice(通知):AOP在特定的切入點上執行的增強處理,有before(前置),after(後置),afterReturning(最終),afterThrowing(異常),around(環繞)
(5)Pointcut(切入點):就是帶有通知的連接點,在程序中主要體現爲書寫切入點表達式
(6)weave(織入):將切面應用到目標對象並導致代理對象創建的過程
(7)introduction(引入):在不修改代碼的前提下,引入可以在運行期爲類動態地添加一些方法或字段
(8)AOP代理(AOP Proxy):AOP框架創建的對象,代理就是目標對象的加強。Spring中的AOP代理可以使JDK動態代理,也可以是CGLIB代理,前者基於接口,後者基於子類
(9)目標對象(Target Object): 包含連接點的對象。也被稱作被通知或被代理對象。POJO

  1. Advice通知類型介紹:

(1)Before:在目標方法被調用之前做增強處理,@Before只需要指定切入點表達式即可
(2)AfterReturning:在目標方法正常完成後做增強,@AfterReturning除了指定切入點表達式後,還可以指定一個返回值形參名returning,代表目標方法的返回值
(3)AfterThrowing:主要用來處理程序中未處理的異常,@AfterThrowing除了指定切入點表達式後,還可以指定一個throwing的返回值形參名,可以通過該形參名
來訪問目標方法中所拋出的異常對象
(4)After:在目標方法完成之後做增強,無論目標方法時候成功完成。@After可以指定一個切入點表達式
(5)Around:環繞通知,在目標方法完成前後做增強處理,環繞通知是最重要的通知類型,像事務,日誌等都是環繞通知,注意編程中核心是一個ProceedingJoinPoint

  1. AOP使用場景:

Authentication 權限
Caching 緩存
Context passing 內容傳遞
Error handling 錯誤處理
Lazy loading 懶加載
Debugging  調試
logging, tracing, profiling and monitoring 記錄跟蹤 優化 校準
Performance optimization 性能優化
Persistence  持久化
Resource pooling 資源池
Synchronization 同步
Transactions 事務

二、關於jar包依賴:

我用的是maven管理jar,具體如下:
pom.xml:

<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.9</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.9</version>
     </dependency>

三、使用AOP的幾種方式:

1.經典的基於代理的AOP
2.@AspectJ註解驅動的切面
3.純POJO切面(純粹通過aop:fonfig標籤配置)
4.注入式AspectJ切面

四、具體使用方式:

一個例子

爲了更好的說明 AOP 的概念,我們來舉一個實際中的例子來說明:

在這裏插入圖片描述

在上面的例子中,包租婆的核心業務就是籤合同,收房租,那麼這就夠了,灰色框起來的部分都是重複且邊緣的事,交給中介商就好了,這就是 AOP 的一個思想:讓關注點代碼與業務代碼分離!

實際的代碼

我們來實際的用代碼感受一下

1.在 Package【pojo】下新建一個【Landlord】類(我百度翻譯的包租婆的英文):

package com.aop.aopdemo.pojo;

import org.springframework.stereotype.Component;

/**
 * @author: zhaohb
 * @create: 2020-01-14 14:44
 **/
@Component("landlord")
public class Landlord {
    public void service() {
        // 僅僅只是實現了核心的業務功能
        System.out.println("籤合同");
        System.out.println("收房租");
    }
}

2.在 Package【aspect】下新建一箇中介商【Broker】類(我還是用的翻譯…):

package com.aop.aopdemo.pojo;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;


/**
 * @author: zhaohb
 * @create: 2020-01-14 14:45
 **/
@Component
@Aspect
public class Broker {
    @Pointcut("execution(* com.aop.aopdemo.pojo.Landlord.service())")
    public void lService() {
    }

    @Before("lService()")
    public void before(){
        System.out.println("帶租客看房");
        System.out.println("談價格");
    }

    @After("lService()")
    public void after(){
        System.out.println("交鑰匙");
    }
}

3.在 Package【aopdemo】下編寫測試代碼:

package com.aop.aopdemo;

import com.aop.aopdemo.pojo.Landlord;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class AopdemoApplication {

    public static void main(String[] args) {
        ApplicationContext app = SpringApplication.run(AopdemoApplication.class, args);
        Landlord landlord = (Landlord) app.getBean("landlord", Landlord.class);
        landlord.service();
    }

}

5.執行看到效果:

"C:\Program Files\Java\jdk1.8.0_131\bin\java.exe" -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=65006 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=localhost -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.4\lib\idea_rt.jar=65007:C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_131\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar;E:\南方電網二期\現場代碼\aopdemo\target\classes;D:\maven\repository\org\springframework\boot\spring-boot-starter\2.2.2.RELEASE\spring-boot-starter-2.2.2.RELEASE.jar;D:\maven\repository\org\springframework\boot\spring-boot\2.2.2.RELEASE\spring-boot-2.2.2.RELEASE.jar;D:\maven\repository\org\springframework\spring-context\5.2.2.RELEASE\spring-context-5.2.2.RELEASE.jar;D:\maven\repository\org\springframework\spring-aop\5.2.2.RELEASE\spring-aop-5.2.2.RELEASE.jar;D:\maven\repository\org\springframework\spring-beans\5.2.2.RELEASE\spring-beans-5.2.2.RELEASE.jar;D:\maven\repository\org\springframework\spring-expression\5.2.2.RELEASE\spring-expression-5.2.2.RELEASE.jar;D:\maven\repository\org\springframework\boot\spring-boot-autoconfigure\2.2.2.RELEASE\spring-boot-autoconfigure-2.2.2.RELEASE.jar;D:\maven\repository\org\springframework\boot\spring-boot-starter-logging\2.2.2.RELEASE\spring-boot-starter-logging-2.2.2.RELEASE.jar;D:\maven\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\maven\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\maven\repository\org\apache\logging\log4j\log4j-to-slf4j\2.12.1\log4j-to-slf4j-2.12.1.jar;D:\maven\repository\org\apache\logging\log4j\log4j-api\2.12.1\log4j-api-2.12.1.jar;D:\maven\repository\org\slf4j\jul-to-slf4j\1.7.29\jul-to-slf4j-1.7.29.jar;D:\maven\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\maven\repository\org\springframework\spring-core\5.2.2.RELEASE\spring-core-5.2.2.RELEASE.jar;D:\maven\repository\org\springframework\spring-jcl\5.2.2.RELEASE\spring-jcl-5.2.2.RELEASE.jar;D:\maven\repository\org\yaml\snakeyaml\1.25\snakeyaml-1.25.jar;D:\maven\repository\org\slf4j\slf4j-api\1.7.29\slf4j-api-1.7.29.jar;D:\maven\repository\org\aspectj\aspectjweaver\1.8.3\aspectjweaver-1.8.3.jar" com.aop.aopdemo.AopdemoApplication

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.2.RELEASE)

2020-01-14 16:29:52.164  INFO 14296 --- [           main] com.aop.aopdemo.AopdemoApplication       : Starting AopdemoApplication on note190257 with PID 14296 (started by zhao_hanbing in E:\南方電網二期\現場代碼\aopdemo)
2020-01-14 16:29:52.168  INFO 14296 --- [           main] com.aop.aopdemo.AopdemoApplication       : No active profile set, falling back to default profiles: default
2020-01-14 16:29:52.726  INFO 14296 --- [           main] com.aop.aopdemo.AopdemoApplication       : Started AopdemoApplication in 0.842 seconds (JVM running for 1.854)
帶租客看房
談價格
籤合同
收房租
交鑰匙

Process finished with exit code 0
發佈了24 篇原創文章 · 獲贊 4 · 訪問量 6366
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章