1. 程式人生 > >Spring Aop 原始碼實現原理分析

Spring Aop 原始碼實現原理分析

更新:2018/4/2 修改字型、新增引言。

0   引言

AOP是Aspect Oriented Programing的簡稱,面向切面程式設計。AOP適合於那些具有橫切邏輯的應用:如效能監測,訪問控制,事務管理、快取、物件池管理以及日誌記錄。AOP將這些分散在各個業務邏輯中的程式碼通過橫向切割的方式抽取到一個獨立的模組中。AOP 實現的關鍵就在於 AOP 框架自動建立的 AOP 代理,AOP 代理則可分為靜態代理和動態代理兩大類,其中靜態代理是指使用 AOP 框架提供的命令進行編譯,從而在編譯階段就可生成 AOP 代理類,因此也稱為編譯時增強;而動態代理則在執行時藉助於 JDK 動態代理、CGLIB 等在記憶體中“臨時”生成 AOP 動態代理類,因此也被稱為執行時增強。


    代理物件的方法 = 增強處理 + 被代理物件的方法
    Spring AOP 則採用執行時生成 AOP 代理類,因此無需使用特定編譯器進行處理。由於 Spring AOP 需要在每次執行時生成 AOP 代理,因此效能略差一    些。

    AOP使用場景:AOP用來封裝橫切關注點,具體可以在下面的場景中使用:

    Authentication 許可權、Caching 快取、Context passing 內容傳遞、Error handling 錯誤處理、Lazy loading 懶載入、Debugging 除錯、logging, tracing, profiling and monitoring 記錄跟蹤 優化 校準、

Performance optimization 效能優化、Persistence 持久化、Resource pooling 資源池、Synchronization 同步、Transactions 事務

1 建立AopProxy代理物件

1.1  配置ProxyFactoryBean

從這部分開始,我們進入到Spring AOP的實現部分,在分析Spring AOP的實現原理中,我們主要以ProxyFactoryBean的實現作為例子和實現的基本線索進行分析。很大一個原因是因為ProxyFactoryBean是在Spring IoC環境中,建立AOP應用的最底層方法,也是最靈活的方法,Spring通過它完成了對AOP使用的封裝,以它的實現為入口逐層深入,是很好的一條幫助我們理解Spring AOP實現的學習路徑。

在瞭解ProxyFactoryBean的實現之前,我們先簡要地瞭解一下ProxyFactoryBean的配置和使用,在基於XML配置Spring的Bean的時候,往往需要一系列的配置步驟來使用ProxyFactoryBean和AOP,比如以下這些步驟:

1)定義使用的通知器Advisor,這個通知器應該作為一個Bean來定義。很重要的一點,這個通知器的實現定義了需要對目標物件進行增強的切面行為,也就是Advice通知。

2)定義proxyFactoryBean,把它作為另一個Bean來定義,它是封裝AOP功能的主要類。在配置ProxyFactoryBean時,需要設定與AOP實現相關的重要屬性,比如ProxyInterface、interceptorNames和target等。從屬性名稱可以看出,interceptorNames屬性的值往往設定為需要定義的通知器,因為這些通知器在ProxyFactoryBean的AOP配置下,是通過使用代理物件的攔截器機制起作用的。所以,這裡依然沿用了攔截器這個名字,也算是舊瓶裝新酒吧。

3)定義target屬性,作為target屬性注入的Bean,是需要用AOP通知器中的切面應用來增強的物件,也就是前面我們提到的base物件。

有了這些配置,就可以使用ProxyFactoryBean完成AOP的基本功能了。關於配置的例子,如程式碼清單3-10所示。與前面提到的配置步驟相對應,除了定義了ProxyFactoryBean的AOP封裝,還定義了一個Advisor,取名為testAdvisor。作為ProxyFactory配置的一部分,還需要配置攔截的方法呼叫介面和目標物件。這些基本的配置,是使用ProxyFactoryBean實現AOP功能的重要組成,對於這些配置的實現和作用機制,也是我們後面重點分析的內容。

程式碼清單3-10  配置ProxyFactoryBean

  1. <bean id="testAdvisor"class="com.abc.TestAdvisor"/>  
  2. <bean id="testAOP"class="org.springframework.aop.ProxyFactoryBean>   
  3.  <property name="proxyInterfaces"><value>com.test.AbcInterface"  
  4.  </value></property>  
  5.  <property name="target">  
  6.     <bean class="com.abc.TestTarget"/>  
  7.   </property>  
  8.   <property name="interceptorNames">  
  9.     <list><value> testAdvisor</value></list>  
  10.   </property>  
  11. </bean> 

掌握這些配置後,就可以具體看一看這些AOP是如何實現的。也就是說,切面應用是怎樣通過ProxyFactoryBean對target物件起作用的。對於這個ProxyFactoryBean,我們先了解一下ProxyFactoryBean的類層次關係,如圖3-8所示。在這個類層次關係中,可以看到用來完成AOP應用的類,比如AspectJProxyFactory、ProxyFactory和ProxyFactoryBean,它們都在同一個類的繼承體系下,都是ProxyConfig、AdvisedSupport和ProxyCreatorSupport的子類。作為大家的共同基類,ProxyConfig可以看成是一個數據類,這個資料基類為像ProxyFactoryBean這樣的子類提供了配置屬性。在另一個基類AdvisedSupport的實現中,它封裝了AOP中對通知和通知器的相關操作,這些操作對於不同的AOP的代理物件的生成都是一樣的,但對於具體的AOP代理物件的建立,AdvisedSupport把它交給它的子類們去完成。ProxyCreatorSupport看成是其子類建立AOP代理物件的一個輔助類,通過繼承以上提到的基類的功能實現,具體的AOP代理物件的生成,根據不同的需要分別由ProxyFactoryBean、AspectJProxyFactory和ProxyFactory來完成。對於需要使用AspectJ的AOP應用,AspectJProxyFactory起到整合Spring和AspectJ的作用;對於使用Spring AOP的應用,ProxyFactoryBean和ProxyFactoy都提供了AOP功能的封裝,只是如果使用ProxyFactoryBean,可以在IoC容器中完成宣告式配置,而使用ProxyFactory,則需要程式設計式的使用Spring AOP的功能;對於它們是如何封裝實現AOP功能的,在本章後面的小節中給出詳細的分析,在這裡,通過這些類層次關係的瞭解,希望能先給讀者留下一個大致的印象。

 

1.2 ProxyFactoryBean生成AopProxy

在Spring AOP的使用中,我們已經瞭解到,可以通過ProxyFactoryBean來配置目標物件和方面行為。這個ProxyFactoryBean是一個FactoryBean,對FactoryBean這種Spring應用中經常出現的Bean的工作形式,讀者一定不會感到陌生,對於FactoryBean的工作原理,我們在結合IoC容器的實現原理分析中已經做過闡述。在ProxyFactoryBean中,通過interceptorNames屬性來配置已經定義好的通知器Advisor。雖然這裡的名字叫interceptNames,但值得注意的是,實際上卻是供AOP應用配置通知器的地方。在ProxyFactoryBean中,需要為target目標物件生成Proxy代理物件,從而為AOP橫切面的編織做好準備工作。

這些具體的代理物件生成工作,在以後的實現原理分析中,我們可以看到是通過JDK的Proxy或CGLIB來完成的。

在ProxyFactoryBean中,它的AOP實現需要依賴JDK或者CGLIB提供的Proxy特性。從FactoryBean中獲取物件,是用getObject()方法作為入口完成的;讓我們進入ProxyFactoryBean的實現中去,這個我們一點也不陌生的getObject方法,是FactoryBean需要實現的介面。對ProxyFactoryBean來說,把需要對target目標物件增加的增強處理,都通過getObject方法進行封裝了,這些增強處理是為AOP功能的實現提供服務的。對於getObject的實現如程式碼清單3-11所示。getObject方法首先對通知器鏈進行初始化,通知器鏈封裝了一系列的攔截器,這些攔截器都要從配置中讀取,然後為代理物件的生成做好準備。在生成代理物件的時候,因為Spring中有sigleton型別和prototype型別這兩種不同的Bean,所以這裡對代理物件的生成需要做一個區分。

程式碼清單3-11 ProxyFactoryBean的getObject

  1. public Object getObject() throws BeansException {
  2. //這裡初始化通知器鏈。
  3. initializeAdvisorChain();
  4. //這裡對singleton和protype的型別進行區分,生成對應的proxy。
  5. if (isSingleton()) {
  6. return getSingletonInstance();
  7. }
  8. else {
  9. if (this.targetName == null) {
  10. logger.warn("Using non-singleton
  11. proxies with singleton targets is
  12. often undesirable. " +
  13. "Enable prototype proxies by setting the 'targetName' property.");
  14. }
  15. return newPrototypeInstance();
  16. }
  17. }

為Proxy代理物件配置Advisor鏈是在initializeAdvisorChain方法中完成的,如程式碼清單3-12所示。這個初始化過程有一個標誌位advisorChainInitialized,這個標誌用來表示通知器鏈是否已經初始化。如果已經初始化,那麼這裡就不會再初始化,而是直接返回。也就是說,這個初始化的工作,發生在應用第一次通過ProxyFactoryBean去獲取代理物件的時候。在完成這個初始化之後,接著會讀取配置中出現的所有通知器,這個取得通知器的過程也比較簡單,把通知器的名字交給容器的getBean方法就可以了,這是通過對IoC容器實現的一個回撥來完成的。然後把從IoC容器中取得的通知器加入到攔截器鏈中,這個動作是由addAdvisorOn-ChainCreation方法來實現的。

程式碼清單3-12 對Advisor配置鏈的初始化

  1. privatesynchronizedvoid initializeAdvisorChain() throws
  2. AopConfigException,
  3. BeansException {
  4. if (this.advisorChainInitialized) {
  5. return;
  6. }
  7. if (!ObjectUtils.isEmpty(this.interceptorNames)) {
  8. if (this.beanFactory == null) {
  9. thrownew IllegalStateException("No
  10. BeanFactory available anymore
  11. (probably due to serialization) " +
  12. "- cannot resolve interceptor names
  13. " + Arrays.asList(this.
  14. interceptorNames));
  15. }
  16. /**
  17. * Globals can't be last unless we specified
  18. a targetSource
  19. * using the property...
  20. */
  21. if
  22. (this.interceptorNames[this.interceptorNames.length -
  23. 1].endsWith
  24. (GLOBAL_SUFFIX) && this.targetName == null &&
  25. this.targetSource ==
  26. EMPTY_TARGET_
  27. SOURCE) {
  28. thrownew AopConfigException("Target
  29. required after globals");
  30. }
  31. // Materialize interceptor chain from bean
  32. names.
  33. //
  34. 這裡是新增advisor鏈的呼叫,是通過interceptorNames屬性來進行
  35. 配置的。
  36. for (String name : this.interceptorNames) {
  37. if (logger.isTraceEnabled()) {
  38. logger.trace("Configuring
  39. advisor or advice '" + name + "'");
  40. }
  41. if (name.endsWith(GLOBAL_SUFFIX)) {
  42. if (!(this.beanFactory
  43. instanceof ListableBeanFactory)) {
  44. thrownew
  45. AopConfigException(
  46. "Can
  47. only use global advisors or interceptors with
  48. a
  49. ListableBeanFactory");
  50. }
  51. addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
  52. name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
  53. }
  54. else {
  55. // If we get here, we need
  56. to add a named interceptor.
  57. // We must check if it's a
  58. singleton or prototype.
  59. Object advice;
  60. if (this.singleton ||
  61. this.beanFactory.isSingleton(name)) {
  62. // Add the real
  63. Advisor/Advice to the chain.
  64. advice =
  65. this.beanFactory.getBean(name);
  66. }
  67. else {
  68. // It's a prototype
  69. Advice or Advisor: replace with a prototype.
  70. /**
  71. *Avoid unnecessary
  72. creation of prototype bean just for
  73. *advisor chain
  74. initialization.
  75. */
  76. advice = new
  77. PrototypePlaceholderAdvisor(name);
  78. }
  79. addAdvisorOnChainCreation(advice, name);
  80. }
  81. }
  82. }
  83. this.advisorChainInitialized = true;
  84. }

生成singleton的代理物件在getSingletonInstance()的程式碼中完成,這個方法是ProxyFactoryBean生成AopProxy代理物件的呼叫入口。在代理物件中會封裝對target目標物件的呼叫,也就是說針對target物件的方法呼叫行為,會被這裡生成的代理物件所攔截。具體的生成過程是,首先需要讀取ProxyFactoryBean中的配置,為生成代理物件做好必要的準備,比如設定代理的方法呼叫介面等。對於在getSingletonInstance()方法中代理物件的生成過程,如程式碼清單3-13所示。

程式碼清單3-13 生成單件代理物件

  1. 相關推薦

    Spring Aop 原始碼實現原理分析

    更新:2018/4/2 修改字型、新增引言。0   引言AOP是Aspect Oriented Programing的簡稱,面向切面程式設計。AOP適合於那些具有橫切邏輯的應用:如效能監測,訪問控制,事務管理、快取、物件池管理以及日誌記錄。AOP將這些分散在各個業務邏輯中的程

    Spring IOC和Spring AOP實現原理(原始碼主線流程)

    寫在前面      正本文參考了《spring技術內幕》和spring 4.0.5原始碼。本文只描述原理流程的主線部分,其他比如驗證,快取什麼可以具體參考原始碼理解。Spring IOC一、容器初始化      容器的初始化首先是在對應的構造器中進行,在application

    Spring技術內幕:Spring AOP實現原理(三)

    dede ide configure ida mini == src min dem 生成SingleTon代理對象在getSingleTonInstance方法中完畢,這種方法時ProxyFactoryBean生成AopProxy對象的入口。代理對象會

    Spring AOP實現原理

    class文件 ndb 是我 反射 ofo 直接 pri 關註 選擇 AOP(Aspect Orient Programming),我們一般稱為面向方面(切面)編程,作為面向對象的一種補充,用於處理系統中分布於各個模塊的橫切關註點,比如事務管理、日誌、緩存等等。AOP實現的

    Spring AOP實現原理

    代碼生成 time .get hand 日誌 aop 分布 class a cee AOP(Aspect Orient Programming),我們一般稱為面向方面(切面)編程,作為面向對象的一種補充,用於處理系統中分布於各個模塊的橫切關註點,比如事務管理、日誌、緩存等等

    springSpring aop實現原理

    本文轉載自https://www.cnblogs.com/lcngu/p/5339555.html。 Spring aop的實現原理 簡介   前段時間寫的java設計模式--代理模式,最近在看Spring Aop的時候,覺得於代理模式應該有密切的聯絡,於是決定了解下Sprin

    反射實現 AOP 動態代理模式例項說明(Spring AOP實現 原理)

    說明以下,spring aop的實現原理不是用java的動態代理。是用代理模式和CGLib (Code GenerationLibrary), 不過現在不用CGLib(Code Generation Library),直接用ASM框架來操作位元組碼了。 好長時間沒有用過S

    Spring AOP IOC 實現原理,面試問到如何回答

    IOC:控制反轉也叫依賴注入,IOC利用java反射機制,AOP利用代理模式。所謂控制反轉是指,本來被呼叫者的例項是有呼叫者來建立的,這樣的缺點是耦合性太強,IOC則是統一交給spring來管理建立,將物件交給容器管理,你只需要在spring配置檔案總配置相應的

    Spring AOP實現原理—— 靜態代理和動態代理

    AOP(Aspect Orient Programming),我們一般稱為面向方面(切面)程式設計,作為面向物件的一種補充,用於處理系統中分佈於各個模組的橫切關注點,比如事務管理、日誌、快取等等。 AOP實現的關鍵在於AOP框架自動建立的AOP代理,

    Spring AOP底層實現原理

    1、spring的AOP底層是由 JDK提供的動態代理技術 和 CGLIB(動態位元組碼增強技術)實現。 2、JDK動態代理:Jdk動態代理只針對於介面操作。 3、CGLIB:可以針

    Spring AOP實現原理(二)

    **二、AOP的設計與實現 1、JVM的動態代理特性** 在Spring AOP實現中, 使用的核心技術時動態代理,而這種動態代理實際上是JDK的一個特性。通過JDK的動態代理特性,可以為任意Java物件建立代理物件,對於具體使用來說,這個特性使通過Java Reflectio

    反射實現 AOP 動態代理模式(Spring AOP實現 原理)

    {40            //反射得到操作者的例項41            Class clazz = this.proxy.getClass();42            //反射得到操作者的Start方法43            Method start = clazz.getDeclaredM

    菜鳥學SSH——Spring容器AOP實現原理——動態代理

    之前寫了一篇關於IOC的部落格——《Spring容器IOC解析及簡單實現》,今天再來聊聊AOP。大家都知道Spring的兩大特性是IOC和AOP。 IOC負責將物件動態的注入到容器,從而達到一種需要誰就注入誰,什麼時候需要就什麼時候注入的效果,可謂是招之則來,揮之則去。想想都覺得爽,如果現實

    Spring AOP原始碼分析

    概述 定義 官方定義:Aspect-Oriented Programming (AOP) complements Object-Oriented Programming (OOP) by providing another way of thinking about prog

    spring事務管理實現原理-原始碼-傳播屬性-工作小結

    本部落格分為兩點,一個是spring事務實現原理原始碼解讀(個人能力,初步解讀),二是spring事務的傳播屬性   簡單案例,儲存訂單,修改商品數量 就是這兩個方法,第一個方法中引用了第二個方法,都用@Transactional註解。debug呼叫shoppi

    Spring-AOP原始碼分析

    一、概述 Spring的兩大特性:IOC和AOP。 AOP是面向切面程式設計,Spring內建了自己實現的基於動態代理技術的AOP,同時還支援成熟的AspectJ框架,我們這裡主要講述的還是內建的基於動態代理的AOP實現。因為面對一些普通的需求,Spring內建的AOP已經綽綽有餘。

    Spring】:aop實現原理

    銜接前篇文章:https://blog.csdn.net/hxcaifly/article/details/85061330 前言 前段時間寫的java設計模式–代理模式,最近在看Spring Aop的時候,覺得於代理模式應該有密切的聯絡,於是決定了解下Spring A

    (二)Spring AOP原始碼-1.概述與設計原理-02設計原理

    AOP實現的關鍵在於自動建立AOP代理,AOP代理可分為靜態代理和動態代理。 靜態代理與動態代理 靜態代理主要在虛擬機器啟動時通過改變目標物件位元組碼的方式完成對目標物件的增強。以靜態代理為基礎實現的AOP技術的代表為AspectJ。Aspect

    Spring實現原理分析(二十四).Spring Boot實現原理分析

    前陣子在分析sprng boot的原始碼,有了些感悟和心得,今天寫篇部落格和大家分享下。先來段題外話,在人體的血液中含有血細胞,而血細胞又大致可以分為紅細胞、白細胞、血小板。它們各自有各自的用處和特點,互相協作保障人體的建康。 一. 各種Bean            如

    通過原始碼深入理解 Spring 事務的實現原理

    如果你現在在使用 Spring 事務,並且存在如下疑問:為什麼會報 Transaction rolled back because it has been marked as rollback-only 異常?Transactional 註解是否可以加在 private、pr