Spring Framework 5 權威指南
這是一個Spring 5專題系列,其誕生的動機是:
1.介紹最新版本的Spring Framework;
2.介紹最系統化的Spring Framework;
3.介紹最佳實踐的Spring Framework;
3.7代理機制
Spring AOP是基於代理的AOP框架(不同於AspectJ),使用標準的JDK動態代理或CGLIB代理來實現AOP代理(默認取決於目標對象是否實現某個介面)。
要強制使用CGLIB代理,配置如下:
等價的基於schema風格的配置如下:
事務是典型的AOP實現,支持同樣的屬性:
注意:
1.final方法不能被覆蓋,因此也不能被通知;
2.從Spring 3.2開始,CGLIB已經打包到spring-core.jar中;
3.從Spring 4.0開始,CGLIB的代理實例通過Objenesis創建,因此不再調用兩次代理類的構造函數;
在下面的代碼片段中:
publicclassSimplePojoimplementsPojo {
publicvoidfoo() {
//this next method invocation is a direct call on the this reference
this.bar();
}
publicvoidbar() {
//some logic...
}
}
如果你在一個對象引用上調用一個方法,方法將直接在該對象引用上被調用。如下:
publicclassMain{
publicstaticvoidmain(String[]args) {
Pojo pojo =newSimplePojo();
//this is a direct method call on the pojo reference
pojo.foo();
}
}
如果客戶端代碼引用的是代理,如圖:
publicclassMain{
publicstaticvoidmain(String[]args) {
ProxyFactory factory =newProxyFactory(newSimplePojo());
factory.addInterface(Pojo.class);
factory.addAdvice(newRetryAdvice());
Pojo pojo = (Pojo)factory.getProxy();
//this is a method call on the proxy!
pojo.foo();
}
}
由於代理的存在,才使得攔截方法的調用成為可能。但是,目標對象中的自調用方法針對的是this而不是代理引用,因此無法進行攔截。兩種解決辦法,一種是重構代碼以消除自調用,另一種方法則比較變態(與Spring AOP耦合),如下:
publicclassSimplePojoimplementsPojo {
publicvoidfoo() {
//this works, but... gah!
((Pojo)AopContext.currentProxy()).bar();
}
publicvoidbar() {
//some logic...
}
}
客戶端代碼如下:
publicclassMain{
publicstaticvoidmain(String[]args) {
ProxyFactory factory =newProxyFactory(newSimplePojo());
factory.adddInterface(Pojo.class);
factory.addAdvice(newRetryAdvice());
factory.setExposeProxy(true);
Pojo pojo = (Pojo)factory.getProxy();
//this is a method call on the proxy!
pojo.foo();
}
}
注意:如果使用AspectJ則不存在自調用這個問題,因為其不是基於代理的AOP框架。
除了聲明方面以外,還可以通過編程的方式來創建@AspectJ代理以通知目標對象:
// create a factory that cangenerate a proxy for the given target object
AspectJProxyFactory factory =newAspectJProxyFactory(targetObject);
// add an aspect, the classmust be an @AspectJ aspect
// you can call this as many timesas you need with different aspects
factory.addAspect(SecurityManager.class);
// you can also add existingaspect instances, the type of the object supplied must be an @AspectJ aspect
factory.addAspect(usageTracker);
// now get the proxyobject...
MyInterfaceType proxy = factory.getProxy();
TODO:暫時放在這裡
Spring團隊推薦使用基於@AspectJ風格的方面聲明勝過基於schema風格的方面聲明。後者使得代碼和配置分離使得關聯關係不夠直接,並且功能也不夠完善:例如只支持方面的單實例化模型、不能引用已定義的切入點。而前者能同時被Spring AOP框架和AspectJ框架理解。但是,兩種方式也可以並存,其底層是一樣的。多個和片段會被合併為一個AutoProxyCreator。
※防彈少年團回歸創紀錄 人氣火爆靠數據說話
※《果園文學》微刊2017年第016期
※世界上最要命的是成為你自己,因為你父母不願意
※孩子不懂寬容?不妨這樣做
※想看「2 One Another」值回票價?這些「秘密」你不可不知……
TAG:全球大搜羅 |