spring之AOP的概念及簡單案例

来源:https://www.cnblogs.com/xshcode/archive/2023/05/20/17415763.html
-Advertisement-
Play Games

# AOP概念 AOP(Aspect Oriented Programming),即面向切麵編程,可以說是OOP(Object Oriented Programming,面向對象編程)的補充和完善。OOP引入封裝、繼承、多態等概念來建立一種對象層次結構,用於模擬公共行為的一個集合。不過OOP允許開發 ...


AOP概念

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

AOP技術恰恰相反,它利用一種稱為"橫切"的技術,剖解開封裝的對象內部,並將那些影響了多個類的公共行為封裝到一個可重用模塊,並將其命名為"Aspect",即切麵。所謂"切麵",簡單說就是那些與業務無關,卻為業務模塊所共同調用的邏輯或責任封裝起來,便於減少系統的重覆代碼,降低模塊之間的耦合度,並有利於未來的可操作性和可維護性。

使用"橫切"技術,AOP把軟體系統分為兩個部分:核心關註點和橫切關註點。業務處理的主要流程是核心關註點,與之關係不大的部分是橫切關註點。橫切關註點的一個特點是,他們經常發生在核心關註點的多處,而各處基本相似,比如許可權認證、日誌、事物。AOP的作用在於分離系統中的各種關註點,將核心關註點和橫切關註點分離開來。

AOP核心概念

Aspect(切麵): Aspect 聲明類似於 Java 中的類聲明,在 Aspect 中會包含著一些 Pointcut 以及相應的 Advice。

Joint point(連接點):表示在程式中明確定義的點,典型的包括方法調用,對類成員的訪問以及異常處理程式塊的執行等等,它自身還可以嵌套其它 joint point。

Pointcut(切點):表示一組 joint point,這些 joint point 或是通過邏輯關係組合起來,或是通過通配、正則表達式等方式集中起來,它定義了相應的 Advice 將要發生的地方。

Advice(增強):Advice 定義了在 Pointcut 裡面定義的程式點具體要做的操作,它通過 before、after 和 around 來區別是在每個 joint point 之前、之後還是代替執行的代碼。

Target(目標對象):織入 Advice 的目標對象.。

Weaving(織入):將 Aspect 和其他對象連接起來, 並創建 Adviced object 的過程

舉例理解

下麵我以一個簡單的例子來比喻一下 AOP 中 Aspect, Joint point, Pointcut 與 Advice之間的關係.

讓我們來假設一下, 從前有一個叫爪哇的小縣城, 在一個月黑風高的晚上, 這個縣城中發生了命案. 作案的凶手十分狡猾, 現場沒有留下什麼有價值的線索. 不過萬幸的是, 剛從隔壁回來的老王恰好在這時候無意中發現了凶手行凶的過程, 但是由於天色已晚, 加上凶手蒙著面, 老王並沒有看清凶手的面目, 只知道凶手是個男性, 身高約七尺五寸. 爪哇縣的縣令根據老王的描述, 對守門計程車兵下命令說: 凡是發現有身高七尺五寸的男性, 都要抓過來審問. 士兵當然不敢違背縣令的命令, 只好把進出城的所有符合條件的人都抓了起來.

來讓我們看一下上面的一個小故事和 AOP 到底有什麼對應關係.
首先我們知道, 在 Spring AOP 中 Joint point 指代的是所有方法的執行點, 而 point cut 是一個描述信息, 它修飾的是 Joint point, 通過 point cut, 我們就可以確定哪些 Joint point 可以被織入 Advice. 對應到我們在上面舉的例子, 我們可以做一個簡單的類比, Joint point 就相當於 爪哇的小縣城裡的百姓,pointcut 就相當於 老王所做的指控, 即凶手是個男性, 身高約七尺五寸, 而 Advice 則是施加在符合老王所描述的嫌疑人的動作: 抓過來審問.
為什麼可以這樣類比呢?

Joint point : 爪哇的小縣城裡的百姓: 因為根據定義, Joint point 是所有可能被織入 Advice 的候選的點, 在 Spring AOP中, 則可以認為所有方法執行點都是 Joint point. 而在我們上面的例子中, 命案發生在小縣城中, 按理說在此縣城中的所有人都有可能是嫌疑人.

Pointcut :男性, 身高約七尺五寸: 我們知道, 所有的方法(joint point) 都可以織入 Advice, 但是我們並不希望在所有方法上都織入 Advice, 而 Pointcut 的作用就是提供一組規則來匹配joinpoint, 給滿足規則的 joinpoint 添加 Advice. 同理, 對於縣令來說, 他再昏庸, 也知道不能把縣城中的所有百姓都抓起來審問, 而是根據凶手是個男性, 身高約七尺五寸, 把符合條件的人抓起來. 在這裡 凶手是個男性, 身高約七尺五寸 就是一個修飾謂語, 它限定了凶手的範圍, 滿足此修飾規則的百姓都是嫌疑人, 都需要抓起來審問.

Advice :抓過來審問, Advice 是一個動作, 即一段 Java 代碼, 這段 Java 代碼是作用於 point cut 所限定的那些 Joint point 上的. 同理, 對比到我們的例子中, 抓過來審問 這個動作就是對作用於那些滿足 男性, 身高約七尺五寸 的爪哇的小縣城裡的百姓.

Aspect::Aspect 是 point cut 與 Advice 的組合, 因此在這裡我們就可以類比: “根據老王的線索, 凡是發現有身高七尺五寸的男性, 都要抓過來審問” 這一整個動作可以被認為是一個 Aspect.

代碼案例

我們首先建立配置類Config,在此類開啟AspectJ註解@EnableAspectJAutoProxy

註意:在最新版本的Spring框架中,@EnableAspectJAutoProxy註解不是必需的。當你使用<aop:aspectj-autoproxy>配置或者Spring Boot時,它會自動啟用AspectJ自動代理。

Spring框架會根據以下條件自動啟用AspectJ自動代理:

  1. 在類路徑下存在AspectJ織入器(例如,AspectJ的相關依賴已經被引入)。
  2. Spring上下文中存在至少一個@Aspect註解的切麵類。

因此,如果你的項目滿足這些條件,你無需顯式地使用@EnableAspectJAutoProxy註解。Spring框架會自動探測並啟用AspectJ自動代理。

Config類:

package com.xsh.springaop;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@ComponentScan
@Configuration
//開啟AspectJ註解
@EnableAspectJAutoProxy
public class Config {
}


下列代碼是一個簡單的AOP切麵示例,用於在目標方法執行之前和執行之後列印日誌。

  1. @Aspect註解表示這是一個切麵類,用於聲明切麵的功能。
  2. @Component註解表示這個切麵類是一個Spring組件,將被Spring容器管理。
  3. @Before("execution(* com.xsh.springaop.MyServer.fun1(..))")註解表示這個方法將在目標方法執行之前執行。它使用了切點表達式來指定切入的連接點。在本例中,切點表達式execution(* com.xsh.springaop.MyServer.fun1(..))表示匹配com.xsh.springaop.MyServer類中的fun1方法,並且方法參數任意。
  4. @After("execution(* com.xsh.springaop.MyServer.fun2(..))")註解表示這個方法將在目標方法執行之後執行。切點表達式與上述相似,匹配com.xsh.springaop.MyServer類中的fun2方法。
  5. beforeMethodExecution()方法是前置通知方法,它在目標方法執行之前被調用,列印了一條日誌信息。
  6. afterAdvice()方法是後置通知方法,它在目標方法執行之後被調用,列印了一條日誌信息。

通過這種方式,可以在不修改原有業務邏輯的情況下,通過AOP切麵對目標方法進行增強操作,例如記錄日誌、性能監控、事務管理等。在示例中,切麵類LoggingAspect將在目標方法執行前後輸出日誌信息。

LoggingAspect:

package com.xsh.springaop;

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



@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.xsh.springaop.MyServer.fun1(..))")
    public void beforeMethodExecution() {
        System.out.println("Before executing method");
    }

    @After("execution(* com.xsh.springaop.MyServer.fun2(..))")
    public void afterAdvice() {
        System.out.println("After executing method");
    }




}


下列代碼是有2個方法,分別對應切麵類中的所切方法。

MyServer:

package com.xsh.springaop;


import org.springframework.stereotype.Service;

@Service
public class MyServer {


    public void fun1() {
        System.out.println("我是方法1111");
    }

    public void fun2(){
        System.out.println("我是方法2222");
    }

}


下列代碼是一個Spring Boot的應用程式啟動類。它實現了CommandLineRunner介面,用於在應用程式啟動後執行一些初始化任務。

  1. @Component註解表示這個類是一個Spring組件,將被Spring容器管理。
  2. AppRunner類實現了CommandLineRunner介面,它定義了一個run方法,在應用程式啟動後會被自動調用。
  3. AppRunner類中,使用@Autowired註解將MyServer類的實例自動註入進來,即將MyServer對象註入到myServer欄位中。
  4. run方法中,調用了myServer對象的fun1()fun2()方法,即執行了目標方法。

通過這種方式,當應用程式啟動後,AppRunner類的run方法將會被自動調用,從而觸發執行MyServer類中的目標方法fun1()fun2()。這樣可以方便地測試和驗證切麵是否生效,是否正確地增強了目標方法的功能。

AppRunner:

package com.xsh.springaop;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class AppRunner implements CommandLineRunner {

    @Autowired
    private MyServer myServer;

    @Override
    public void run(String... args) throws Exception {
        myServer.fun1();
        myServer.fun2();
    }
}



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一.業務描述 最近在負責公司一個語音的微服務模塊優化,這個模塊主要的業務是:1.天貓精靈、小度、若琪、小京魚、小愛同學、思必馳這些第三方音響對我們的用戶進行oauth2/JWT授權; 2.這些第三方音響服務調用我們的設備發現介面對公司的設備信息在第三方平臺進行一個存儲;3.第三方平臺對用戶發出的語音 ...
  • 關於JWT,可以說是分散式系統下的一個利器,我在我的很多項目實踐中,認證系統的第一選擇都是JWT。它的優勢會讓你欲罷不能,就像你領優惠券一樣。 ...
  • ## 創建阻塞的 EchoClient 客戶程式一般不需要同時建立與伺服器的多個連接,因此用一個線程,按照阻塞模式運行就能滿足需求 ```java public class EchoClient { private SocketChannel socketChannel = null; public ...
  • ## 1. 安裝Django 在命令行中輸入以下命令安裝Django ```shell pip install django ``` ## 2. 創建Django項目 在命令行中輸入以下命令創建一個名為myblog的Django項目 ```shell django-admin startprojec ...
  • ## 文章首發 [【重學C++】01| C++ 如何進行記憶體資源管理?](https://mp.weixin.qq.com/s/ZhRhN07wjypnkWXcu_Lz3g) ## 前言 大家好,我是只講技術乾貨的會玩code,今天是【重學C++】的第一講,我們來學習下C++的記憶體管理。 與java ...
  • 前言: 最近生產環境系統發現一個疑難雜症,看了很久的問題但是始終無法定位到問題並處理,然後查閱了相關資料也是定位不到問題,不過資料查閱卻給了個新的思路,以此為跳板最終解決了問題。 一、問題描述 功能介紹: “主計劃拆分子計劃”是APS系統很常見的功能,功能大概意思是用戶可選多個主計劃一次性進行“展開 ...
  • 本文圍繞 Spring Boot 中如何讓你的 bean 在其他 bean 之前完成載入展開討論。 問題 今天有個小伙伴給我出了一個難題:在 SpringBoot 中如何讓自己的某個指定的 Bean 在其他 Bean 前完成被 Spring 載入?我聽到這個問題的第一反應是,為什麼會有這樣奇怪的需求 ...
  • IDEA常用設置(提高開發效率) IDEA是一款當前比較主流的編譯器,我個人也用的比較多,但是有時出於各種原因,比如更換設備等等,IDEA總是需要重新安裝配置。這就讓我比較苦惱,因為總是記不全自己之前都修改了哪些地方(原諒腦子不好使hh),所以就以此篇文章記錄一下目前我的IDEA的設置情況。可能依舊 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...