帶你瞭解如何使用Spring基於ProxyFactoryBean創建AOP代理

若使用 Spring IoC 容器(ApplicationContext或BeanFactory)作為你的業務對象(你也應該這麼做!),你會想使用 Spring AOP FactoryBean的一種。

工廠 bean 引入瞭中間層,讓它創建不同類型的對象。

在Spring創建 AOP 代理的基本方式是使用 org.springframework.aop.framework.ProxyFactoryBean。這可以完全控制pointcuts、使用的任何通知和他們的順序。但若不需要這樣的控制,也有更簡單的選擇。

1 基礎

ProxyFactoryBean,類似其他 Spring 的FactoryBean實現,引入瞭中間層。

若你定義瞭名為 foo 的ProxyFactoryBean,則引用 foo 的對象不會看到ProxyFactoryBean實例本身,而是在ProxyFactoryBean中實現的 getObject()創建的對象。該方法創建瞭一個包裝目標對象的 AOP 代理。

使用ProxyFactoryBean或其他 IoC-aware 類創建 AOP 代理的最大好處之一是advices和pointcuts也可以由 IoC 管理。這是一個強大的功能,使某些方法很難用AOP 實現的開啟瞭新途徑。例如,advice本身可能引用應用對象(不僅是目標對象,該對象應在任何 AOP 框架中都可用),從而受益於DI提供的所有可插拔性。

2 JavaBean屬性

與大多數FactoryBean實現類似, ProxyFactoryBean類本身就是一個JavaBean。

其屬性用於:

  • 指定要代理的目標
  • 指定是否使用 CGLIB

一些關鍵屬性是從 org.springframework.aop.framework.ProxyConfig (Spring所有 Aop 代理工廠的父類) 繼承的。這些關鍵屬性包括:

  • proxyTargetClass

如果要代理目標類,而不是目標類的接口,則為 true。如果此屬性值設置為true,則創建 CGLIB 代理

  • optimize

控制是否將主動優化應用於通過 CGLIB 創建的代理。除非你完全瞭解相關的 AOP 代理如何處理優化,否則您不應輕率地使用此設置。僅用於 CGLIB 代理,對 JDK 動態代理無影響。

  • frozen

如果代理配置被凍結,則不再允許更改配置。這既是一種輕微的優化,也是在不希望調用者在創建代理後(通過建議的接口)操縱代理時,這些情況是有用的。默認值false,即允許更改(比如添加額外advice)。

  • exposeProxy

確定當前代理是否應在ThreadLocal暴露,以便目標可以訪問該代理。如果目標需要獲取代理並將暴露的 Proxy 屬性設置為true,則目標可以使用 AopContext.當前普羅西 () 方法。

ProxyFactoryBean其他屬性包括:

  • proxyInterfaces

字符串接口名稱的數組。若不提供此,則使用目標類的 CGLIB 代理

  • interceptorNames

要應用的Advisor、攔截器或其他建議名稱的字符串數組。順序非常重要,首先先到先得。也就是說,列表中的第一個攔截器是能夠攔截調用的第一個攔截器。

這些名稱是當前工廠中的bean名稱,包括來自祖先工廠的bean名稱。你不能在這裡使用bean引用, 因為這樣做會導致

ProxyFactoryBean忽略瞭推薦的單例設置。

可以用 * 附加攔截器名稱。這樣做會導致應用所有advisor beans與名稱,開始與*應用前的部分。

  • singleton

工廠是否應該返回單例的對象,無論getObject()調用頻率如何,幾個FactoryBean實現都提供這樣的方法。默認值為true。如果你想使用有狀態的advice,使用prototype 類型的advices以及false的singleton值。

3 JDK和CGLIB代理

ProxyFactoryBean如何選擇為特定目標對象(將代理)創建基於 JDK 的代理或基於 CGLIB 的代理。

ProxyFactoryBean在創建基於 JDK 或 CGLIB 的代理方面的行為在Spring的 1.2.x 版本和 2.0
版本之間發生瞭變化。ProxyFactoryBean現在在自動檢測接口方面表現出與TransactionProxyFactoryBean類類似的語義。

如果要代理的目標對象類別(以下簡稱目標類)不實現任何接口,則創建基於 CGLIB 的代理。這是最簡單的方案,因為 JDK 代理是基於接口的,沒有接口意味著 JDK 代理甚至是不可能的。您可以插入目標豆,並通過設置攔截器命名屬性來指定攔截器列表。請註意,即使代理工廠豆的代理目標類屬性被設置為虛假,也創建基於 CGLIB 的代理。(這樣做是沒有意義的,最好從豆的定義中刪除,因為它充其量是多餘的,而且,在最壞的情況下是令人困惑的。

總結

本篇文章就到這裡瞭,希望能給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!

推薦閱讀: