1. 程式人生 > >做一個合格的程式猿之淺析Spring AOP原始碼(十五) 分析JdkDynamicAopProxy的invoke方法

做一個合格的程式猿之淺析Spring AOP原始碼(十五) 分析JdkDynamicAopProxy的invoke方法

 上一節我們已經分析了Proxyfactorybean如何去生成一個目標物件的代理的,這一節我們將淺析一下基於JDK動態代理的核心回撥方法invoke的原始碼:

首先先開啟JdkDynamicAopProxy.java 如下

JdkDynamicAopProxy.java檔案是實現了AopProxy和InvocationHandler這2個介面的

先講AopProxy這個介面,如圖所示,AopProxy介面就定義了2個方法

我們再看這個介面的繼承關係

好了,作為原生的基於JDK的動態代理的JdkDynamicAopProxy已經很完美的返回了目標物件的代理,詳細請看上一節內容

http://blog.csdn.net/linuu/article/details/50972036

再分析InvocationHandler這個介面,這個介面核心的方法就是invoke方法


invoke這個方法首先先定義了一些變數,暫時不看

上圖中的紅色框中有三個if:

第一個if是判斷如果被代理的目標物件要執行的方法是equal則執行JdkDynamicAopProxy(即代理物件的equal)方法,然後就返回了,也就說spring不對equal方法進行AOP攔截

第二個if是判斷如果被代理的目標物件要執行的方法是hashcode則執行JdkDynamicAopProxy(即代理物件的hashcode)方法,隨即也返回,同理,spring也不對hashcode進行AOP攔截

第三個if是判斷如果被代理的物件本身就是實現了Advised介面,也不做處理,直接執行,(spring的意思是不是我不做切面的切面呢?)

接著看下一個核心方法

看官方的英文註釋,就知道目前要做的就是獲取一下這個方法所有的攔截器,形成攔截鏈返回,進入getInterceptorsAndDynamicInterceptionAdvice這個方法

479和480兩行是從快取中尋找該方法的攔截鏈是否已經獲取過(可能被代理物件的某個方法被呼叫過多次,呼叫第一次就會獲取一次,後面多次呼叫時,則需從快取中直接獲取,無需多次獲取,這樣就會提高效能),如果已經獲取過,直接返回

好了,我們這邊肯定是第一次呼叫,接著看getInterceptorsAndDynamicInterceptionAdvice這個方法

上圖中①部分先定義了一個攔截鏈的List大小最大為我們傳入advisor的個數,然後檢視我們傳入的advisor是否也是IntroductionAdvisor這個介面的子類,IntroductionAdvisor這個介面我們沒有分析過,這應該是基於類的攔截器,不能攔截類中的具體方法,沒有PointcutAdvisor靈活,我們這邊瞭解一下就可以了

然後程式要做的事就是迴圈每個我們傳入的advisor,然後強轉成pointAdvisor,②中最核心的就是當前攔截是否匹配當前要執行代理的方法(其實也就是判斷當前的advisor的切點是否就是這樣方法),我們上節講過我們闖入的pointCut是一個“萬能”的pointCut:

我們再看matches這個方法

這就是這個萬能的pointcut能切類的任何方法的原因了(其實這邊就是一個攔截器的過濾,應該我們在生產環境中,我們一般會用正則表達來定義切點(expression),因為並不是每個方法都需要切,會影響效能,所以②中matches這個方法很重要)

如果匹配了,則把其放入方法一上來就定義的interceptorList中

我們回到JdkDynamicAopProxy的invoke方法中,接著看

此時我們的攔截鏈當然不是空的,直接分析else,invocation就是invoke方法中第一行就定義的MethodInvocation,這裡的invocation其實就是把所有的引數準備好:

引數整理就是把我們之前的代理,目標物件,攔截的method的名稱,攔截方法的引數和攔截器鏈全部整合到了ReflectiveMethodInvocation這個類中

各位看官想一下,ReflectiveMethodInvocation這個類有了這麼多的引數,就可以幹自己想幹的任何是,首先它可以直接執行目標物件的那個方法(有目標類的class,名稱,引數)就可以執行了(怎麼執行?別鬧,名稱寫的很清楚了,Reflect!!!!),並且有了攔截器鏈,只要知道攔截器的型別是前置,後置,環繞的型別,就可以吧攔截器也給執行了,所以所有的東西一切都準備就緒了~

最後我們看看執行的過程吧 proceed()方法

好了,我們來看看spring如何執行的,首先線看攔截器鏈,預設從-1個執行(get(-1)?錯了,下文先++this.currentInterceptorIndex,這樣就從第0個開始執行攔截器

spring判斷我們的切面是否是需要動態匹配切點,我們這邊就是很普通的萬能切點,所以不需要,不管是什麼樣的切點,最後都執行了invoke方法,且將自己傳入(ReflectiveMethodInvocation)

因為我們實現的是MethodBeforeAdviceInterceptor


這邊就是執行我們在MethodInvokeCountAdvice,和MethodLoggerAdvice實現的before方法this.currentInterceptorIndex

然後再遞迴呼叫,與上次不一樣的是this.currentInterceptorIndex這個+1了,所以會執行下一個攔截器,到了最後一個會走:

最後執行切入點,也就是我們目標物件的方法

到此為止關於proxyFactoryBean基本就講結束了,還是希望自己debug看看吧~

相關推薦

一個合格程式淺析Spring AOP原始碼 分析JdkDynamicAopProxy的invoke方法

 上一節我們已經分析了Proxyfactorybean如何去生成一個目標物件的代理的,這一節我們將淺析一下基於JDK動態代理的核心回撥方法invoke的原始碼: 首先先開啟JdkDynamicAop

一個合格程式淺析Spring IoC原始碼Spring refresh()方法解析後記1

上次分析refresh這塊spring IoC的時候,時間比較倉促,只是debug了部分原始碼,大家分析起來不是很好~ 今天我們還是先總結一下吧~ spring在例項化bean的時候,根據bean

一個合格程式淺析Spring IoC原始碼Spring refresh()方法解析之一

經過上面幾節的簡單介紹我們瞭解了spring的一些元件,現在我們來分析一下AbstractApplicationContext中的refresh()這個核心方法吧~ 用我們上一節的程式碼,debug進入refresh方法: public void refresh() th

一個合格程式淺析Spring IoC原始碼Spring Bean的初始化順序

上幾節我們比較詳細地說明了一下BeanFactoryPostProcessor和BeanPostProcessor這2個介面的作用和意義,並且也花了一個章節,講了一下BeanFactory和FactoryBean的關係,最後我們也稍微說明了一下BeanFactoryAwar

spring深入學習 IOC 從單例快取中獲取單例 bean

從這篇部落格開始我們開始載入 bean 的第一個步驟,從快取中獲取 bean,程式碼片段如下: Object sharedInstance = getSingleton(beanName); if (sharedInstance != null &&

機器學習numpy和matplotlib學習

今天來學習矩陣的建立和一些基本運算 #!/usr/bin/env python # -*- coding: utf-8 -*- # @Author : SundayCoder-俊勇 # @File : numpy7.py import numpy as np # numpy基

Spring.NET教程AOP的配置(基礎篇)

上篇我學習了Spring.net的四種通知型別,AOP的實現方案比較複雜,是通過程式碼實現的。而Spring.NET框架給我們提供了配置的方式來實現AOP的功能。到目前為止,我們已經討論過使用ProxyFactoryObject或其它類似的工廠物件顯式建立AOP代理的方法。如果應用程式需要建立很多AOP代理,

spring-boot-route整合RocketMQ

## RocketMQ簡介 RocketMQ是阿里巴巴開源的訊息中介軟體。目前已經貢獻給Apache軟體基金會,成為Apache的頂級專案。 ### rocketMQ基本概念 ![](https://img2020.cnblogs.com/blog/1719198/202010/1719198-2020

程式---C語言細節9巨集定義、maxa,b巨集定義細節、大小端判斷、(int&)a什麼意思

主要內容:巨集定義、max(a,b)巨集定義細節、大小端判斷、(int&)a什麼意思 #if 1 #include <stdio.h> // 注意空格 #define F (x) ((x) - 1) // F代表後面 #define F(x)

python學習網站的編寫HTML,CSS,JS----------示例,彈出一個背景為半黑色,前面是白框的彈窗功能已經編好的框架

效果圖,程式碼直接可應用,按自己的需要在其中加入想要的內容:  程式碼及講解: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <

spring深入學習 IOC Factory 例項化 bean

這篇我們關注建立 bean 過程中的第一個步驟:例項化 bean,對應的方法為:createBeanInstance(),如下: protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd

spring深入學習 IOC 開啟 bean 的例項化程序

在上篇部落格【死磕 Spring】—– 載入 bean 之 分析各 scope 的 bean 建立中有一個核心方法沒有講到 createBean(),該方法的如下: protected abstract Object createBean(String beanName, RootBe

spring深入學習 IOC 分析各 scope 的 bean 建立

在 Spring 中存在著不同的 scope,預設是 singleton ,還有 prototype、request 等等其他的 scope,他們的初始化步驟是怎樣的呢?這個答案在這篇部落格中給出。 singleton Spring 的 scope 預設為 singleton,其初始化的程式

spring深入學習 IOC parentBeanFactory 與依賴處理

繼上篇部落格 【死磕 Spring】—– 載入 bean 之 快取中獲取單例 bean,如果從單例快取中沒有獲取到單例 bean,則說明兩種情況: 該 bean 的 scope 不是 singleton 該 bean 的 scope 是 singleton ,但是沒有初始化

spring深入學習 IOC 開啟 bean 的載入

(此圖來自《Spring 揭祕》) Spring IOC 容器所起的作用如上圖所示,它會以某種方式載入 Configuration Metadata,將其解析註冊到容器內部,然後回根據這些資訊繫結整個系統的物件,最終組裝成一個可用的基於輕量級容器的應用系統。 Spring 在實現上述功

Spring 學習——AOP 基礎動態代理

AOP 前奏 WHY  AOP ? 需求1-日誌:在程式執行期間追蹤正在發生的活動 需求2-驗證:希望計算器只能處理正數的運算 程式碼實現片段       問題 •程式碼混亂:越來越多的非業務需求(日誌和驗證等)

一個轉行程式設計師的工作經歷與感想後期更新

前言 隨著科技的發展,現代人生活的節奏是越來越快,個人覺得程式設計師的生活節奏更快(個人觀點),在忙碌的生活中總是很難找到一點點的空閒時間(就算有,估計也是用來睡眠,不知道為什麼總是感覺程式設計師是一種睡眠不足的生物),但是一旦有時間就想通過文字記錄下來,作為以後生活的回憶

OSGI企業應用開發基於Spring、Mybatis、Spring MVC實現一個登入應用

前面文章中,我們已經完成了OSGI應用中Spring、Mybatis、Spring MVC的整合,本篇文章我們就在這個基礎上來完成一個簡單的登入應用,其中使用者名稱和密碼需要從資料庫中查詢。 前面文章中,我們已經搭建好的工作空間如下圖所示: 本篇文章中,

spring-boot-route整合redis為快取

## redis簡介 redis作為一種非關係型資料庫,讀寫非常快,應用十分廣泛,它採用key-value的形式儲存資料,value常用的五大資料型別有string(字串),list(連結串列),set(集合),zset(有序集合)和hash(雜湊表)。 redis的特性決定了它的功能,它可以用來做以下這

OpenCV探索:角點檢測

回調函數 閾值 source and 類型 幾何 擁有 .com named 角點檢測是計算機視覺系統中用來獲取圖像特征的一種方法。我們都常說,這幅圖像很有特點,但是一問他到底有哪些特點,或者這幅圖有哪些特征可以讓你一下子就識別出該物體,你可能就說不出來了。其實說圖像的特征