Spring aop 的代理機制

Spring aop 的代理機制

Spring aop 的代理機制


Spring aop 是通過代理實現的,代理有靜態代理,jdk動態代理和cglib動態代理,代理就像我們生活中的房產中介,你不直接與房主,銀行接觸,而是通過中介與他們溝通聯繫。

代理的結構如圖所示:

Spring aop 的代理機制

Spring aop 的代理機制


RealSubject 和 Proxy都實現了相同的接口Subject,Proxy持有RealSubject的引用,但Client 調用 request方法時,Proxy將請求轉發給RealSubject,其中可以添加各種訪問控制。

但是靜態代理有一個弊端,需要為每一個目標類創建一個代理類,如果需要代理的對象很多的話,就得編寫相應的代理類,於是jdk動態代理出現了,它主要用了 java.lang.reflect.Proxy類和java.lang.reflect.InvocationHandler接口。

我們先實現java.lang.reflect.InvocationHandler,添加需要的橫切邏輯

public

class

AccessControl

implements

InvocationHandler

{
@Override
public

Object
invoke
(
Object
proxy
,

Method
method
,

Object
[]
args
)

throws

Throwable

{
//調用前的處理

System
.
out
.
println
(
"調用前驗證"
);

Object
obj
=
method
.
invoke
(
proxy
,
args
);
//調用後的處理

System
.
out
.
println
(
"調用後處理"
);

return
obj
;
}
}

然後通過Proxy為不同的類型生成相應的代理對象。

Proxy
.
newProxyInstance
(
targertClass1
.
getClassLoader
(),
targertClass1
.
getInterfaces
(),
accessControl
);
Proxy
.
newProxyInstance
(
targertClass2
.
getClassLoader
(),
targertClass2
.
getInterfaces
(),
accessControl
);

不管targetClass有多少類型,都可以通過Proxy生成具有相同訪問控制accesControl的代理對象。

從上面示例可知jdk動態代理需要被代理類實現接口(Interface),對於沒有實現任何接口的目標對象,我們就要另找方法了。默認情況下,當Spring發現目標對象沒有實現任何接口時,會使用CGLIB,為目標對象動態生成代理對象,其實質就是對目標對象進行繼承,生成子類,子類覆蓋父類的方法,在其中加入額外的訪問控制,不過如果類中的方法聲明為final的話,就不能對它進行擴展。

Spring 創建代理的秘密在DefaultAopProxyFactory 類中可以找到:

public

AopProxy
createAopProxy
(
AdvisedSupport
config
)

throws

AopConfigException

{

if

(
config
.
isOptimize
()

||
config
.
isProxyTargetClass
()

||
hasNoUserSuppliedProxyInterfaces
(
config
))

{

Class
targetClass
=
config
.
getTargetClass
();

if


(
targetClass
==

null
)

{

throw

new

AopConfigException
(
"TargetSource cannot determine target class: "
\+
"Either an interface or a target is required for proxy creation."
);

}

if

(
targetClass
.
isInterface
())

{

return

new

JdkDynamicAopProxy
(
config
);

}

return

CglibProxyFactory
.
createCglibProxy
(

config
);

}

else

{

return

new

JdkDynamicAopProxy
(
config
);

}
}

如果isOptimize()返回true,或者proxyTargetClass屬性為true,或者目標對象沒有接口實現,就採用cglib動態代理,否則就用jdk動態代理。再看看JdkDynamicAopProxy中的getProxy

public

Object
getProxy
(
ClassLoader
classLoader
)

{

if

(
logger
.
isDebugEnabled
())

{
logger
.

debug
(
"Creating JDK dynamic proxy: target source is "

+

this
.
advised
.
getTargetSource
());

}

Class
[]
proxiedInterfaces
=

AopProxyUtils
.
completeProxiedInterfaces
(
this
.
advised
);
findDefinedEqualsAndHashCodeMethods
(
proxiedInterfaces
);

return

Proxy
.
newProxyInstance
(
classLoader
,
proxiedInterfaces
,

this
);
}

請看最後一行代碼,是否有似曾相識之感。

Spring aop 僅作用於方法,如果你想對構造方法或字段作攔截處理,就要引入AspectJ,它支持在編譯期間織入橫切邏輯,提高運行期間的性能,但在易用性和靈活性上不如Spring aop。值得注意的是,Spring中@AspectJ註解區別的切面也是基於Spring aop 的代理機制實現的,不要被這個名稱混淆了。

加Java架構師進階交流群獲取Java工程化、高性能及分佈式、高性能、深入淺出。高架構。性能調優、Spring,MyBatis,Netty源碼分析和大數據等多個知識點高級進階乾貨的直播免費學習權限 都是大牛帶飛 讓你少走很多的彎路的 群號是:883922439 對了 小白勿進 最好是有開發經驗

注:加群要求

1、具有工作經驗的,面對目前流行的技術不知從何下手,需要突破技術瓶頸的可以加。

2、在公司待久了,過得很安逸,但跳槽時面試碰壁。需要在短時間內進修、跳槽拿高薪的可以加。

3、如果沒有工作經驗,但基礎非常紮實,對java工作機制,常用設計思想,常用java開發框架掌握熟練的,可以加。

4、覺得自己很牛B,一般需求都能搞定。但是所學的知識點沒有系統化,很難在技術領域繼續突破的可以加。

5.阿里Java高級大牛直播講解知識點,分享知識,多年工作經驗的梳理和總結,帶著大家全面、科學地建立自己的技術體系和技術認知!


分享到:


相關文章: