spring——AOP原理及源碼(一)

来源:https://www.cnblogs.com/Unicron/archive/2020/03/01/12386776.html
-Advertisement-
Play Games

教程共分為五篇,從AOP實例的構建及其重要組件、基本運行流程、容器創建流程、關鍵方法調用、原理總結歸納等幾個方面一步步走進AOP的世界。 本篇主要為讀者演示構建AOP實例及AOP核心組件分析。 一、項目構建 讀者可直接下載示例工程,或複製以下的代碼到本地工程開啟教程。 <?xml version=" ...


教程共分為五篇,從AOP實例的構建及其重要組件、基本運行流程、容器創建流程、關鍵方法調用、原理總結歸納等幾個方面一步步走進AOP的世界。

本篇主要為讀者演示構建AOP實例及AOP核心組件分析。

 

一、項目構建

讀者可直接下載示例工程,或複製以下的代碼到本地工程開啟教程。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.tlj</groupId>
    <artifactId>spring-test</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.3.13.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.13.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.44</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
    </dependencies>


</project>
pom.xml
package config;

import aop.LogAspects;
import aop.MathCalculator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@EnableAspectJAutoProxy
@Configuration
public class ConfigOfAOP {

    @Bean
    public MathCalculator calculator(){
        return new MathCalculator();
    }

    @Bean
    public LogAspects logAspects(){
        return new LogAspects();
    }
}
ConfigOfAOP
package aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;

import java.util.Arrays;

/**
 * 切麵類
 */
@Aspect
public class LogAspects {

    @Pointcut("execution(public int aop.MathCalculator.*(..))")
    public void poinCut(){}

    @Before("poinCut()")
    public void logStart(JoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        System.out.println(joinPoint.getSignature().getName()+" 運行。。。@Before "+ Arrays.asList(args));
    }

    @After("poinCut()")
    public void  logEnd(){
        System.out.println("除法結束..@After");
    }

    @AfterReturning(value = "poinCut()",returning = "result")//獲取方法返回值
    public void logReturning(Object result){
        System.out.println("除法正常返回..@AfterReturning "+result);
    }

    @AfterThrowing(value = "poinCut()",throwing = "e")
    public void logException(Exception e){
        System.out.println("除法異常..@AfterThrowing "+e);
    }
}
LogAspects
package aop;

public class MathCalculator {

    public int div(int i,int j){
        System.out.println("MathCalculator");
        return i/j;
    }
}
MathCalculator

項目目錄結構如下:

到這裡,我們的項目是構建完了。

 

 

二、日誌切麵方法測試

打開測試類,運行測試方法

 我們可以看到,總共列印了四行,除了第二行列印是業務方法的調用,其他都是調用日誌切麵類中的方法列印出來的。

這就是AOP的使用效果,除了用在日誌,還有其他很多用法,這裡就不贅述了。

 

 

三、關鍵組件探究

為什麼AOP能在業務方法調用的前後和發生異常時調用切麵方法呢,首先我們需要瞭解它引入了什麼組件。

為了讓AOP起作用,我們需要在配置類上添加@EnableAspectJAutoProxy註解,從字面上看,翻譯為啟動切麵自動代理,那它是怎麼啟動的呢

ctrl+滑鼠左鍵進入這個註解,我們可以看到EnableAspectJAutoProxy介面使用@Import註解導入了AspectJAutoProxyRegistrar這個類

再次ctrl+滑鼠左鍵進入AspectJAutoProxyRegistrar,可以看到,它實現了ImportBeanDefinitionRegistrar介面。

此介面中的registerBeanDefinitions方法,正是用來像容器中註冊組件的。

看來想要知道@EnableAspectJAutoProxy註解到底給容器中添加了什麼組件,我們需要進行調試,找到ImportBeanDefinitionRegistrar方法給容器中添加的組件。這個組件一定就是AOP實現的關鍵。

 

 

 四、調試尋找組件

如下圖,我們在ImportBeanDefinitionRegistrar介面的註冊方法中打上斷點。

 

點擊debug開始調試,程式來到了AspectJAutoProxyRegistrar的registerBeanDefinitions方法

正在執行的是AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry),方法的字面意思:註冊切麵自動代理創造組件如果需要的話

 

接著進入這個方法直到以下這個方法,可以看到返回的是BeanDefinition類型,說明在方法裡面有組件定義或註冊相關的動作。

 110行進行判斷,如果容器中存在AUTO_PROXY_CREATOR_BEAN_NAME這個定義信息,進行以下判斷,巴拉巴拉,最後return null,退出這個方法。

如果不存在,可以看到在125行已經有註冊名為AUTO_PROXY_CREATOR_BEAN_NAME的組件的動作。

把滑鼠放在AUTO_PROXY_CREATOR_BEAN_NAME上,可以看到它實際是叫internalAutoProxyCreator

接著我們進行下一步,到110行時,顯然第一次它是不存在這個類的,所以跳過if{}中的內容,到121行時,我們可以看看cls的信息,發現這個類叫AnnotationAwareAspectJAutoProxyCreator

 

 到125行時,已經設置好AnnotationAwareAspectJAutoProxyCreator的各種屬性,將其命名為internalAutoProxyCreator註冊進容器,在126行進行返回。

在上面過程中,我們可以得到的結論是,@EnableAspectJAutoProxy註解實際上就是給容器中添加了名為internalAutoProxyCreator的組件,實際就是AnnotationAwareAspectJAutoProxyCreator這個類。

我們可以得出AnnotationAwareAspectJAutoProxyCreator就是實現AOP的核心組件。

接下來我們來探究一下AnnotationAwareAspectJAutoProxyCreator的繼承關係,以及它是什麼。

 

 

五、AnnotationAwareAspectJAutoProxyCreator組件是什麼

進入這個類,發現它繼承了AspectJAwareAdvisorAutoProxyCreator

 

那麼AspectJAwareAdvisorAutoProxyCreator又是什麼呢,接著進入AspectJAwareAdvisorAutoProxyCreator

發現AspectJAwareAdvisorAutoProxyCreator又繼承了AbstractAdvisorAutoProxyCreator

我們接著進入AbstractAdvisorAutoProxyCreator中查看

可以看到AbstractAdvisorAutoProxyCreator繼承了AbstractAutoProxyCreator

再進入AbstractAutoProxyCreator

可以看到AbstractAutoProxyCreator繼承了ProxyProcessorSupport

並實現了SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware兩個介面

 

 接下來我們主要看這兩個介面

SmartInstantiationAwareBeanPostProcessor明顯是一個後置處理器介面,BeanFactoryAware是一個底層組件介面,實現BeanFactoryAware就可以註入並調用BeanFactory。

經過層層的進入,可以得到如下的關係

這樣看來,我們可以得出結論——AnnotationAwareAspectJAutoProxyCreator是一個後置處理器後置處理器原理

 

 

總結

  經過以上五個步驟,我們看到AOP的使用效果,發現了AOP的核心組件AnnotationAwareAspectJAutoProxyCreator是一個後置處理器,理清了AnnotationAwareAspectJAutoProxyCreator的繼承實現關係。

總得來說,就是明白了核心組件是什麼。

 

在接下來的篇章我們將從核心組件在哪發揮作用,何時發揮,以及做了什麼,一步步深入原理。


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

-Advertisement-
Play Games
更多相關文章
  • 目錄 1. 隱式類型轉換 2. 顯示類型轉換/強制類型轉換( static_cast、const_cast、reinterpret_cast、dynamic_cast) 3. 類型轉換函數、轉換構造函數 類型轉換可分為 隱式類型轉換(編譯器自動完成) 與 顯示類型轉換(強制類型轉換,需要自己操作)。 ...
  • 先用一個數組表示一個二叉樹搜索樹,也就是一個排好序的二叉樹,其中左子結點<根結點<右子結點 利用結構數組的形式來表示,id , left , right 代表結點id ,左子樹 ,右子樹 下麵這個二維數組 $data[]=['id'=>8,'left'=>2,'right'=>10,'data'=> ...
  • 上一篇我們已經根據路徑讀取到了我們需要的位元組碼文件,就以java.lang.Object這個類為例,可以看到類似下麵這種東西,那麼這些數字是什麼呢? 要瞭解這個,我們大概可以猜到這是十進位的,線上將十進位轉為十六進位看看https://tool.oschina.net/hexconvert/,註意上 ...
  • [TOC] 下麵介紹pandas常見的基本功能,和python的基本數據類型進行比較可以看到pandas在操作大型數據集中的優勢。 1.重建索引 (1)函數:reindex (2)作用:創建一個符合新索引的新對象。 (3)內容: Series調用reindex方法時,會將數組按照新的索引進行排列,如 ...
  • 基於JSP+Servlet開發失物招領系統開發環境: Windows操作系統開發工具:Myeclipse+Jdk+Tomcat7+MYSQL資料庫運行效果圖 源碼及原文鏈接:https://javadao.xyz/forum.php?mod=viewthread&tid=115 ...
  • 基於JSP+Servlet開發公交線上查詢(前臺+後臺):( 開發環境: Windows操作系統開發工具: Eclipse+Jdk+Tomcat+MYSQL資料庫運行效果圖 源碼及原文鏈接:https://javadao.xyz/forum.php?mod=viewthread&tid=120 ...
  • @[toc] 1. Spring註解的源碼分析 1.1 我如何開始分析源碼的? ==這一部分可以略過直接看第1.2節== 想必程式員都會經過這樣一個階段,當 已經能夠熟練運用。並且它的 也能夠用到 ,程式員就會找進階的入口,這時候就想到了去瞭解源碼。 作為Java程式員,首先想到的一定是瞭解Spri ...
  • React非常快速是因為它從不直接操作DOM。 虛擬DOM是在DOM的基礎上建立了一個抽象層,對數據和狀態所做的任何改動,都會被自動且高效的同步到虛擬DOM,最後再批量同步到DOM中。 在React中,render執行的結果得到的並不是真正的DOM節點,而僅僅是JavaScript對象,稱之為虛擬D ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...