做一個合格的程式猿之淺析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(巨集定義、max(a,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 角點檢測是計算機視覺系統中用來獲取圖像特征的一種方法。我們都常說,這幅圖像很有特點,但是一問他到底有哪些特點,或者這幅圖有哪些特征可以讓你一下子就識別出該物體,你可能就說不出來了。其實說圖像的特征