什么是AOP面向切面編程?怎么簡單理解?

本文原文地址:什么是AOP面向切面編程?怎么簡單理解?

什么是AOP面向切面編程

面向切面編程(AOP)通過將橫切關注點(cross-cutting concerns)分離出來,提供了一種增強代碼模塊化和可維護性的方法。

簡單來說,AOP就是將公共的模塊封裝成公共的方法,然后在需要的時候(這個就是切入點),直接就可以調用,而不用在各個對象里面具體的實現(xiàn)。

AOP是一種新的編程方式,它和OOP不同,OOP把系統(tǒng)看作多個對象的交互,AOP把系統(tǒng)分解為不同的關注點,或者稱之為切面(Aspect)。這個可以理解為把系統(tǒng)理解為一個流程,一個對象負責流程上的一個節(jié)點。

當然,AOP和公共模塊抽取調用的方式的差別在于切入點的調用方式的不同。AOP是通過某種方式(下面AOP原理會解釋)自動的調用,而不管是抽取公共方法,還是通過Proxy模式實現(xiàn)調用,都需要在每個業(yè)務方法上重復編寫調用。

以AOP的視角來編寫上述業(yè)務,可以依次實現(xiàn):

  • 核心邏輯,即BookService;
  • 切面邏輯,即:
    1. 權限檢查的Aspect;
    2. 日志的Aspect;
    3. 事務的Aspect。

然后,以某種方式,讓框架來把上述3個Aspect以Proxy的方式“織入”到BookService中,這樣一來,就不必編寫復雜而冗長的Proxy模式或者公共方法調用。

AOP原理

如何把切面織入到核心邏輯中?這正是AOP需要解決的問題。換句話說,如果客戶端獲得了BookService的引用,當調用bookService.createBook()時,如何對調用方法進行攔截,并在攔截前后進行安全檢查、日志、事務等處理,就相當于完成了所有業(yè)務功能。

在Java平臺上,對于AOP的織入,有3種方式:

  1. 編譯期:在編譯時,由編譯器把切面調用編譯進字節(jié)碼,這種方式需要定義新的關鍵字并擴展編譯器,AspectJ就擴展了Java編譯器,使用關鍵字aspect來實現(xiàn)織入;
  2. 類加載器:在目標類被裝載到JVM時,通過一個特殊的類加載器,對目標類的字節(jié)碼重新“增強”;
  3. 運行期:目標對象和切面都是普通Java類,通過JVM的動態(tài)代理功能或者第三方庫實現(xiàn)運行期動態(tài)織入。

最簡單的方式是第三種,Spring的AOP實現(xiàn)就是基于JVM的動態(tài)代理。由于JVM的動態(tài)代理要求必須實現(xiàn)接口,如果一個普通類沒有業(yè)務接口,就需要通過CGLIB或者Javassist這些第三方庫實現(xiàn)。

AOP技術看上去比較神秘,但實際上,它本質就是一個動態(tài)代理,讓我們把一些常用功能如權限檢查、日志、事務等,從每個業(yè)務方法中剝離出來。

需要特別指出的是,AOP對于解決特定問題,例如事務管理非常有用,這是因為分散在各處的事務代碼幾乎是完全相同的,并且它們需要的參數(shù)(JDBC的Connection)也是固定的。另一些特定問題,如日志,就不那么容易實現(xiàn),因為日志雖然簡單,但打印日志的時候,經常需要捕獲局部變量,如果使用AOP實現(xiàn)日志,我們只能輸出固定格式的日志,因此,使用AOP時,必須適合特定的場景。

核心概念

  • 切面(Aspect):切面是封裝橫切關注點的模塊。它定義了在何處以及如何應用這些關注點。
  • 連接點(Join Point):連接點是程序執(zhí)行過程中可以插入切面的點。例如,方法調用、方法執(zhí)行、構造函數(shù)調用、字段訪問等。
  • 切入點(Pointcut):切入點定義了在哪些連接點上應用切面。它通常使用表達式來匹配特定的連接點。
  • 通知(Advice):通知是在特定的切入點上執(zhí)行的代碼。通知可以在方法執(zhí)行之前、之后或異常拋出時執(zhí)行。常見的通知類型包括:
    • 前置通知(Before):在方法執(zhí)行之前執(zhí)行。
    • 后置通知(After):在方法執(zhí)行之后執(zhí)行。
    • 返回通知(After Returning):在方法成功返回之后執(zhí)行。
    • 異常通知(After Throwing):在方法拋出異常之后執(zhí)行。
    • 環(huán)繞通知(Around):包圍方法的執(zhí)行,可以在方法執(zhí)行之前和之后自定義行為。
  • 織入(Weaving):織入是將切面應用到目標對象的過程??椚肟梢栽诰幾g時、類加載時或運行時進行。

示例

以下是一個使用 Spring AOP 的簡單示例,展示了如何定義和應用切面。

  1. 定義切面
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class LoggingAspect {

    @Before("execution(* com.example.service.*.*(..))")
    public void logBeforeMethod() {
        System.out.println("Method is about to be executed");
    }
}

在這個示例中,LoggingAspect 是一個切面,它包含一個前置通知 logBeforeMethod。這個通知將在 com.example.service 包中的所有方法執(zhí)行之前運行。

  1. 配置 Spring AOP
    在 Spring 配置文件中啟用 AOP 支持,并注冊切面:
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd">

    <aop:aspectj-autoproxy/>

    <bean id="loggingAspect" class="com.example.aspect.LoggingAspect"/>
</beans>
  1. 使用目標對象
package com.example.service;

public class UserService {
    public void createUser() {
        System.out.println("Creating user");
    }
}
  1. 測試 AOP
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.example.service.UserService;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) context.getBean("userService");
        userService.createUser();
    }
}

運行這個示例時,輸出將會是:

Method is about to be executed
Creating user

這表明前置通知在 createUser 方法執(zhí)行之前被調用了。

AOP 通過將橫切關注點分離出來,提供了一種增強代碼模塊化和可維護性的方法。通過定義切面、連接點、切入點和通知,可以在不修改現(xiàn)有代碼的情況下,動態(tài)地將橫切關注點織入到程序中。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容