一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務(wù)器之家 - 編程語言 - JAVA教程 - 深入淺析Spring 的aop實現(xiàn)原理

深入淺析Spring 的aop實現(xiàn)原理

2020-04-14 11:36ngulc JAVA教程

AOP(Aspect-OrientedProgramming,面向方面編程),可以說是OOP(Object-Oriented Programing,面向?qū)ο缶幊蹋┑难a充和完善。本文給大家介紹Spring 的aop實現(xiàn)原理,感興趣的朋友一起學(xué)習(xí)吧

什么是AOP

AOP(Aspect-OrientedProgramming,面向方面編程),可以說是OOP(Object-Oriented Programing,面向?qū)ο缶幊蹋┑难a充和完善。OOP引入封裝、繼承和多態(tài)性等概念來建立一種對象層次結(jié)構(gòu),用以模擬公共行為的一個集合。當(dāng)我們需要為分散的對象引入公共行為的時候,OOP則顯得無能為力。也就是說,OOP允許你定義從上到下的關(guān)系,但并不適合定義從左到右的關(guān)系。例如日志功能。日志代碼往往水平地散布在所有對象層次中,而與它所散布到的對象的核心功能毫無關(guān)系。對于其他類型的代碼,如安全性、異常處理和透明的持續(xù)性也是如此。這種散布在各處的無關(guān)的代碼被稱為橫切(cross-cutting)代碼,在OOP設(shè)計中,它導(dǎo)致了大量代碼的重復(fù),而不利于各個模塊的重用。

簡介

  前段時間寫的java設(shè)計模式--代理模式,最近在看Spring Aop的時候,覺得于代理模式應(yīng)該有密切的聯(lián)系,于是決定了解下Spring Aop的實現(xiàn)原理。

  說起AOP就不得不說下OOP了,OOP中引入封裝、繼承和多態(tài)性等概念來建立一種對象層次結(jié)構(gòu),用以模擬公共行為的一個集合。但是,如果我們需要為部分對象引入公共部分的時候,OOP就會引入大量重復(fù)的代碼。例如:日志功能。

  AOP技術(shù)利用一種稱為“橫切”的技術(shù),解剖封裝的對象內(nèi)部,并將那些影響了多個類的公共行為封裝到一個可重用模塊,這樣就能減少系統(tǒng)的重復(fù)代碼,降低模塊間的耦合度,并有利于未來的可操作性和可維護性。AOP把軟件系統(tǒng)分為兩個部分:核心關(guān)注點和橫切關(guān)注點。業(yè)務(wù)處理的主要流程是核心關(guān)注點,與之關(guān)系不大的部分是橫切關(guān)注點。橫切關(guān)注點的一個特點是,他們經(jīng)常發(fā)生在核心關(guān)注點的多處,而各處都基本相似。比如權(quán)限認(rèn)證、日志、事務(wù)處理。

實現(xiàn)原理  

  前面在學(xué)習(xí)代理模式的時候,了解到代理模式分為動態(tài)代理和靜態(tài)代理。現(xiàn)在我們就以代理模式為基礎(chǔ)先實現(xiàn)我們自己的AOP框架,再來研究Spring的AOP的實現(xiàn)原理。

  先以靜態(tài)代理實現(xiàn),靜態(tài)代理關(guān)鍵是在代理對象和目標(biāo)對象實現(xiàn)共同的接口,并且代理對象持有目標(biāo)對象的引用。

  公共接口代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface IHello {
/**
* 業(yè)務(wù)方法
* @param str
*/
void sayHello(String str);
}
  目標(biāo)類代碼:
 
public class Hello implements IHello{
@Override
public void sayHello(String str) {
System.out.println("hello "+str);
}
}

  代理類代碼,我們給它添加日志記錄功能,在方法開始前后執(zhí)行特定的方法,是不是和AOP特別像呢?

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class ProxyHello implements IHello{
private IHello hello;
public ProxyHello(IHello hello) {
super();
this.hello = hello;
}
@Override
public void sayHello(String str) {
Logger.start();//添加特定的方法
hello.sayHello(str);
Logger.end();
}
}

  日志類代碼:

?
1
2
3
4
5
6
7
8
public class Logger {
public static void start(){
System.out.println(new Date()+ " say hello start...");
}
public static void end(){
System.out.println(new Date()+ " say hello end");
}
}

  測試代碼:

?
1
2
3
4
5
6
7
public class Test {
public static void main(String[] args) {
IHello hello = new ProxyHello(new Hello());//如果我們需要日志功能,則使用代理類
//IHello hello = new Hello();//如果我們不需要日志功能則使用目標(biāo)類
hello.sayHello("明天");
}
}

  這樣我們就實現(xiàn)了一個最簡單的AOP,但是這樣會存在一個問題:如果我們像Hello這樣的類很多,那么,我們是不是要去寫很多個HelloProxy這樣的類呢。其實也是一種很麻煩的事。在jdk1.3以后,jdk跟我們提供了一個API java.lang.reflect.InvocationHandler的類, 這個類可以讓我們在JVM調(diào)用某個類的方法時動態(tài)的為些方法做些什么事。下面我們就來實現(xiàn)動態(tài)代理的實現(xiàn)。

  動態(tài)代理實現(xiàn)主要是實現(xiàn)InvocationHandler,并且將目標(biāo)對象注入到代理對象中,利用反射機制來執(zhí)行目標(biāo)對象的方法。

  接口實現(xiàn)與靜態(tài)代理相同,代理類代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class DynaProxyHello implements InvocationHandler{
private Object target;//目標(biāo)對象
/**
* 通過反射來實例化目標(biāo)對象
* @param object
* @return
*/
public Object bind(Object object){
this.target = object;
return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
Logger.start();//添加額外的方法
//通過反射機制來運行目標(biāo)對象的方法
result = method.invoke(this.target, args);
Logger.end();
return result;
}
}

  測試類代碼:

?
1
2
3
4
5
6
7
public class DynaTest {
public static void main(String[] args) {
IHello hello = (IHello) new DynaProxyHello().bind(new Hello());//如果我們需要日志功能,則使用代理類
//IHello hello = new Hello();//如果我們不需要日志功能則使用目標(biāo)類
hello.sayHello("明天");
}
}

  看完上面的代碼可能和Spring AOP相比有一個問題,日志類只能在方法前后打印,但是AOP應(yīng)該是可以在滿足條件就可以執(zhí)行,所有是否可以將DynaPoxyHello對象和日志操作對象(Logger)解耦呢?

  看下面代碼實現(xiàn),將將DynaPoxyHello對象和日志操作對象(Logger)解耦:

  我們要在被代理對象的方法前面或者后面去加上日志操作代碼(或者是其它操作的代碼),那么,我們可以抽象出一個接口,這個接口里就只有兩個方法:一個是在被代理對象要執(zhí)行方法之前執(zhí)行的方法,我們?nèi)∶麨閟tart,第二個方法就是在被代理對象執(zhí)行方法之后執(zhí)行的方法,我們?nèi)∶麨閑nd。

  Logger的接口:

?
1
2
3
4
public interface ILogger {
void start(Method method);
void end(Method method);
}

  Logger的接口實現(xiàn):

?
1
2
3
4
5
6
7
8
9
10
public class DLogger implements ILogger{
@Override
public void start(Method method) {
System.out.println(new Date()+ method.getName() + " say hello start...");
}
@Override
public void end(Method method) {
System.out.println(new Date()+ method.getName() + " say hello end");
}
}

 動態(tài)代理類:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class DynaProxyHello implements InvocationHandler{
//調(diào)用對象
private Object proxy;
//目標(biāo)對象
private Object target;
public Object bind(Object target,Object proxy){
this.target=target;
this.proxy=proxy;
return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
//反射得到操作者的實例
Class clazz = this.proxy.getClass();
//反射得到操作者的Start方法
Method start = clazz.getDeclaredMethod("start", new Class[]{Method.class});
//反射執(zhí)行start方法
start.invoke(this.proxy, new Object[]{this.proxy.getClass()});
//執(zhí)行要處理對象的原本方法
method.invoke(this.target, args);
//反射得到操作者的end方法
Method end = clazz.getDeclaredMethod("end", new Class[]{Method.class});
//反射執(zhí)行end方法
end.invoke(this.proxy, new Object[]{method});
return result;
}
}

  測試代碼:

?
1
2
3
4
5
6
7
public class DynaTest {
public static void main(String[] args) {
IHello hello = (IHello) new DynaProxyHello().bind(new Hello(),new DLogger());//如果我們需要日志功能,則使用代理類
//IHello hello = new Hello();//如果我們不需要日志功能則使用目標(biāo)類
hello.sayHello("明天");
}
}

  通過上面例子,可以發(fā)現(xiàn)通過動態(tài)代理和發(fā)射技術(shù),已經(jīng)基本實現(xiàn)了AOP的功能,如果我們只需要在方法執(zhí)行前打印日志,則可以不實現(xiàn)end()方法,這樣就可以控制打印的時機了。如果我們想讓指定的方法打印日志,我們只需要在invoke()方法中加一個對method名字的判斷,method的名字可以寫在xml文件中,這樣我們就可以實現(xiàn)以配置文件進行解耦了,這樣我們就實現(xiàn)了一個簡單的spring aop框架。

以上內(nèi)容是小編給大家介紹的Spring 的aop實現(xiàn)原理 ,希望對大家有所幫助!

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲va国产日韩欧美精品色婷婷 | 久久久精品国产免费A片胖妇女 | 506070老熟肥妇bbwxx视频 500第一精品 | 成人精品在线 | 538亚洲欧美国产日韩在线精品 | 免费av在线视频 | 国产高清不卡码一区二区三区 | 欧美18一19性高清hd4k | 国产第7页 | ts人妖另类国产 | 国产激情视频网站 | 免费片在线观看高清 | 日韩精品中文字幕视频一区 | 99视频全部看免费观 | 久久囯产精品777蜜桃传媒 | jux629三浦理惠子在线播放 | 国产欧美又粗又猛又爽老 | 91精品综合久久久久久五月天 | 亚洲ⅴa偷拍在线影院 | 男人看片网址 | 女王调奴丨vk| 亚洲图片二区 | 四虎小视频 | 亚洲免费福利视频 | fc2成人免费共享视频 | 99热久久这里只精品国产www | 日韩欧美推理片免费在线播放 | 亚洲国产成人在线 | 久久伊人影院 | 国产肥臀 | 精品小视频在线观看 | 欧美亚洲天堂网 | 久久re这里精品23 | 国产偷窥 | 青青草原网 | 亚洲一区二区三区免费视频 | 国产盗摄wc厕所撒尿视频 | 激情综合色啪啪小说 | 亚洲国产精品久久网午夜 | 国产成年人 | 884aa在线看片 |