日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

轉(zhuǎn):反射實(shí)現(xiàn) AOP 動(dòng)態(tài)代理模式(Spring AOP的實(shí)

系統(tǒng) 2059 0

好長(zhǎng)時(shí)間沒(méi)有用過(guò)Spring了. 突然拿起書.我都發(fā)現(xiàn)自己對(duì)AOP都不熟悉了.
其實(shí)AOP的意思就是面向切面編程.
OO注重的是我們解決問(wèn)題的方法(封裝成Method),而AOP注重的是許多解決解決問(wèn)題的方法中的共同點(diǎn),是對(duì)OO思想的一種補(bǔ)充!
還是拿人家經(jīng)常舉的一個(gè)例子講解一下吧:
比如說(shuō),我們現(xiàn)在要開發(fā)的一個(gè)應(yīng)用里面有很多的業(yè)務(wù)方法,但是,我們現(xiàn)在要對(duì)這個(gè)方法的執(zhí)行做全面監(jiān)控,或部分監(jiān)控.也許我們就會(huì)在要一些方法前去加上一條日志記錄,
我們寫個(gè)例子看看我們最簡(jiǎn)單的解決方案
我們先寫一個(gè)接口IHello.java代碼如下:

?1 package ?sinosoft.dj.aop.staticaop;
?2
?3 public ? interface ?IHello? {
?4 ???? /**
?5 ?????*?假設(shè)這是一個(gè)業(yè)務(wù)方法
?6 ?????*? @param ?name
?7 ????? */

?8 ???? void ?sayHello(String?name);
?9 }

10


里面有個(gè)方法,用于輸入"Hello" 加傳進(jìn)來(lái)的姓名;我們?nèi)憘€(gè)類實(shí)現(xiàn)IHello接口

package ?sinosoft.dj.aop.staticaop;

public ? class ?Hello? implements ?IHello? {

???? public ? void ?sayHello(String?name)? {
????????System.out.println("Hello?"?+?name);
????}


}


現(xiàn)在我們要為這個(gè)業(yè)務(wù)方法加上日志記錄的業(yè)務(wù),我們?cè)诓桓淖冊(cè)a的情況下,我們會(huì)去怎么做呢?也許,你會(huì)去寫一個(gè)類去實(shí)現(xiàn)IHello接口,并依賴Hello這個(gè)類.代碼如下:

?1 package ?sinosoft.dj.aop.staticaop;
?2
?3 public ? class ?HelloProxy? implements ?IHello? {
?4 ???? private ?IHello?hello;
?5
?6 ???? public ?HelloProxy(IHello?hello)? {
?7 ???????? this .hello?=?hello;
?8 ????}

?9
10 ???? public ? void ?sayHello(String?name)? {
11 ????????Logger.logging(Level.DEBUGE,?"sayHello?method?start .");
12 ????????hello.sayHello(name);
13 ????????Logger.logging(Level.INFO,?"sayHello?method?end!");
14
15 ????}

16
17 }

18


其中.Logger類和Level枚舉代碼如下:
Logger.java

?1 package ?sinosoft.dj.aop.staticaop;
?2
?3 import ?java.util.Date;
?4
?5 public ? class ?Logger {
?6 ???? /**
?7 ?????*?根據(jù)等級(jí)記錄日志
?8 ?????*? @param ?level
?9 ?????*? @param ?context
10 ????? */

11 ???? public ? static ? void ?logging(Level?level,?String?context)? {
12 ???????? if ?(level.equals(Level.INFO))? {
13 ????????????System.out.println( new ?Date().toLocaleString()?+?"?"?+?context);
14 ????????}

15 ???????? if ?(level.equals(Level.DEBUGE))? {
16 ????????????System.err.println( new ?Date()?+?"?"?+?context);
17 ????????}

18 ????}

19
20 }

21

Level.java

1 package ?sinosoft.dj.aop.staticaop;
2
3 public ? enum ?Level? {
4 ????INFO,DEBUGE;
5 }

6

那我們?nèi)憘€(gè)測(cè)試類看看,代碼如下:
Test.java

1 package ?sinosoft.dj.aop.staticaop;
2
3 public ? class ?Test? {
4 ???? public ? static ? void ?main(String[]?args)? {
5 ????????IHello?hello?=? new ?HelloProxy( new ?Hello());
6 ????????hello.sayHello("Doublej");
7 ????}

8 }

9

運(yùn)行以上代碼我們可以得到下面結(jié)果:

Tue?Mar?04?20:57:12?CST?2008?sayHello?method?start .
Hello?Doublej
2008-3-4?20:57:12?sayHello?method?end!


從上面的代碼我們可以看出,hello對(duì)象是被HelloProxy這個(gè)所謂的代理態(tài)所創(chuàng)建的.這樣,如果我們以后要把日志記錄的功能去掉.那我們只要把得到hello對(duì)象的代碼改成以下:

1 package ?sinosoft.dj.aop.staticaop;
2
3 public ? class ?Test? {
4 ???? public ? static ? void ?main(String[]?args)? {
5 ????????IHello?hello?=? new ?Hello();
6 ????????hello.sayHello("Doublej");
7 ????}

8 }

9


上面代碼,可以說(shuō)是AOP最簡(jiǎn)單的實(shí)現(xiàn)!
但是我們會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題,如果我們像Hello這樣的類很多,那么,我們是不是要去寫很多個(gè)HelloProxy這樣的類呢.沒(méi)錯(cuò),是的.其實(shí)也是一種很麻煩的事.在jdk1.3以后.jdk跟我們提供了一個(gè)API?? java.lang.reflect.InvocationHandler的類. 這個(gè)類可以讓我們?cè)贘VM調(diào)用某個(gè)類的方法時(shí)動(dòng)態(tài)的為些方法做些什么事.讓我們把以上的代碼改一下來(lái)看看效果.
同樣,我們寫一個(gè)IHello的接口和一個(gè)Hello的實(shí)現(xiàn)類.在接口中.我們定義兩個(gè)方法;代碼如下 :

IHello.java

?1 package ?sinosoft.dj.aop.proxyaop;
?2
?3 public ? interface ?IHello? {
?4 ???? /**
?5 ?????*?業(yè)務(wù)處理A方法
?6 ?????*? @param ?name
?7 ????? */

?8 ???? void ?sayHello(String?name);
?9 ???? /**
10 ?????*?業(yè)務(wù)處理B方法
11 ?????*? @param ?name
12 ????? */

13 ???? void ?sayGoogBye(String?name);
14 }

15



Hello.java?

?1 package ?sinosoft.dj.aop.proxyaop;
?2
?3 public ? class ?Hello? implements ?IHello? {
?4
?5 ???? public ? void ?sayHello(String?name)? {
?6 ????????System.out.println("Hello?"?+?name);
?7 ????}

?8 ???? public ? void ?sayGoogBye(String?name)? {
?9 ????????System.out.println(name+"?GoodBye!");
10 ????}

11 }

12


我們一樣的去寫一個(gè)代理類.只不過(guò).讓這個(gè)類去實(shí)現(xiàn)java.lang.reflect.InvocationHandler接口,代碼如下:

?1 package ?sinosoft.dj.aop.proxyaop;
?2
?3 import ?java.lang.reflect.InvocationHandler;
?4 import ?java.lang.reflect.Method;
?5 import ?java.lang.reflect.Proxy;
?6
?7 public ? class ?DynaProxyHello? implements ?InvocationHandler? {
?8
?9 ???? /**
10 ?????*?要處理的對(duì)象(也就是我們要在方法的前后加上業(yè)務(wù)邏輯的對(duì)象,如例子中的Hello)
11 ????? */

12 ???? private ?Object?delegate;
13
14 ???? /**
15 ?????*?動(dòng)態(tài)生成方法被處理過(guò)后的對(duì)象?(寫法固定)
16 ?????*?
17 ?????*? @param ?delegate
18 ?????*? @param ?proxy
19 ?????*? @return
20 ????? */

21 ???? public ?Object?bind(Object?delegate)? {
22 ???????? this .delegate?=?delegate;
23 ???????? return ?Proxy.newProxyInstance(
24 ???????????????? this .delegate.getClass().getClassLoader(),? this .delegate
25 ????????????????????????.getClass().getInterfaces(),? this );
26 ????}

27 ???? /**
28 ?????*?要處理的對(duì)象中的每個(gè)方法會(huì)被此方法送去JVM調(diào)用,也就是說(shuō),要處理的對(duì)象的方法只能通過(guò)此方法調(diào)用
29 ?????*?此方法是動(dòng)態(tài)的,不是手動(dòng)調(diào)用的
30 ????? */

31 ???? public ?Object?invoke(Object?proxy,?Method?method,?Object[]?args)
32 ???????????? throws ?Throwable? {
33 ????????Object?result?=? null ;
34 ???????? try ? {
35 ???????????? // 執(zhí)行原來(lái)的方法之前記錄日志
36 ????????????Logger.logging(Level.DEBUGE,?method.getName()?+?"?Method?end? .");
37 ????????????
38 ???????????? // JVM通過(guò)這條語(yǔ)句執(zhí)行原來(lái)的方法(反射機(jī)制)
39 ????????????result?=?method.invoke( this .delegate,?args);
40 ???????????? // 執(zhí)行原來(lái)的方法之后記錄日志
41 ????????????Logger.logging(Level.INFO,?method.getName()?+?"?Method?Start!");
42 ????????}
? catch ?(Exception?e)? {
43 ????????????e.printStackTrace();
44 ????????}

45 ???????? // 返回方法返回值給調(diào)用者
46 ???????? return ?result;
47 ????}

48
49 }

50


上面類中出現(xiàn)的Logger類和Level枚舉還是和上一上例子的實(shí)現(xiàn)是一樣的.這里就不貼出代碼了.

讓我們寫一個(gè)Test類去測(cè)試一下.代碼如下:
Test.java

?1 package ?sinosoft.dj.aop.proxyaop;
?2
?3 public ? class ?Test? {
?4 ???? public ? static ? void ?main(String[]?args)? {
?5 ????????IHello?hello?=?(IHello) new ?DynaProxyHello().bind( new ?Hello());
?6 ????????hello.sayGoogBye("Double?J");
?7 ????????hello.sayHello("Double?J");
?8 ????????
?9 ????}

10 }

11


運(yùn)行輸出的結(jié)果如下:

Tue?Mar?04?21:24:03?CST?2008?sayGoogBye?Method?end? .
Double?J?GoodBye!
2008-3-4?21:24:03?sayGoogBye?Method?Start!
Tue?Mar?04?21:24:03?CST?2008?sayHello?Method?end? .
Hello?Double?J
2008-3-4?21:24:03?sayHello?Method?Start!


由于線程的關(guān)系,第二個(gè)方法的開始出現(xiàn)在第一個(gè)方法的結(jié)束之前.這不是我們所關(guān)注的!
從上面的例子我們看出.只要你是采用面向接口編程,那么,你的任何對(duì)象的方法執(zhí)行之前要加上記錄日志的操作都是可以的.他(DynaPoxyHello)自動(dòng)去代理執(zhí)行被代理對(duì)象(Hello)中的每一個(gè)方法,一個(gè)java.lang.reflect.InvocationHandler接口就把我們的代理對(duì)象和被代理對(duì)象解藕了.但是,我們又發(fā)現(xiàn)還有一個(gè)問(wèn)題,這個(gè)DynaPoxyHello對(duì)象只能跟我們?nèi)ピ诜椒ㄇ昂蠹由先罩居涗浀牟僮?我們能不能把DynaPoxyHello對(duì)象和日志操作對(duì)象(Logger)解藕呢?
結(jié)果是肯定的.讓我們來(lái)分析一下我們的需求.
我們要在被代理對(duì)象的方法前面或者后面去加上日志操作代碼(或者是其它操作的代碼),
那么,我們可以抽象出一個(gè)接口,這個(gè)接口里就只有兩個(gè)方法,一個(gè)是在被代理對(duì)象要執(zhí)行方法之前執(zhí)行的方法,我們?nèi)∶麨閟tart,第二個(gè)方法就是在被代理對(duì)象執(zhí)行方法之后執(zhí)行的方法,我們?nèi)∶麨閑nd .接口定義如下 :

?1 package ?sinosoft.dj.aop.proxyaop;
?2
?3 import ?java.lang.reflect.Method;
?4
?5 public ? interface ?IOperation? {
?6 ???? /**
?7 ?????*?方法執(zhí)行之前的操作
?8 ?????*? @param ?method
?9 ????? */

10 ???? void ?start(Method?method);
11 ???? /**
12 ?????*?方法執(zhí)行之后的操作
13 ?????*? @param ?method
14 ????? */

15 ???? void ?end(Method?method);
16 }

17


我們?nèi)懸粋€(gè)實(shí)現(xiàn)上面接口的類.我們把作他真正的操作者,如下面是日志操作者的一個(gè)類:
LoggerOperation.java

package ?sinosoft.dj.aop.proxyaop;

import ?java.lang.reflect.Method;

public ? class ?LoggerOperation? implements ?IOperation? {

???? public ? void ?end(Method?method)? {
????????Logger.logging(Level.DEBUGE,?method.getName()?+?"?Method?end? .");
????}


???? public ? void ?start(Method?method)? {
????????Logger.logging(Level.INFO,?method.getName()?+?"?Method?Start!");
????}


}


然后我們要改一下代理對(duì)象DynaProxyHello中的代碼.如下:

?1 package ?sinosoft.dj.aop.proxyaop;
?2
?3 import ?java.lang.reflect.InvocationHandler;
?4 import ?java.lang.reflect.Method;
?5 import ?java.lang.reflect.Proxy;
?6
?7 public ? class ?DynaProxyHello? implements ?InvocationHandler? {
?8 ???? /**
?9 ?????*?操作者
10 ????? */

11 ???? private ?Object?proxy;
12 ???? /**
13 ?????*?要處理的對(duì)象(也就是我們要在方法的前后加上業(yè)務(wù)邏輯的對(duì)象,如例子中的Hello)
14 ????? */

15 ???? private ?Object?delegate;
16
17 ???? /**
18 ?????*?動(dòng)態(tài)生成方法被處理過(guò)后的對(duì)象?(寫法固定)
19 ?????*?
20 ?????*? @param ?delegate
21 ?????*? @param ?proxy
22 ?????*? @return
23 ????? */

24 ???? public ?Object?bind(Object?delegate,Object?proxy)? {
25 ????????
26 ???????? this .proxy?=?proxy;
27 ???????? this .delegate?=?delegate;
28 ???????? return ?Proxy.newProxyInstance(
29 ???????????????? this .delegate.getClass().getClassLoader(),? this .delegate
30 ????????????????????????.getClass().getInterfaces(),? this );
31 ????}

32 ???? /**
33 ?????*?要處理的對(duì)象中的每個(gè)方法會(huì)被此方法送去JVM調(diào)用,也就是說(shuō),要處理的對(duì)象的方法只能通過(guò)此方法調(diào)用
34 ?????*?此方法是動(dòng)態(tài)的,不是手動(dòng)調(diào)用的
35 ????? */

36 ???? public ?Object?invoke(Object?proxy,?Method?method,?Object[]?args)
37 ???????????? throws ?Throwable? {
38 ????????Object?result?=? null ;
39 ???????? try ? {
40 ???????????? // 反射得到操作者的實(shí)例
41 ????????????Class?clazz?=? this .proxy.getClass();
42 ???????????? // 反射得到操作者的Start方法
43 ????????????Method?start?=?clazz.getDeclaredMethod("start",
44 ???????????????????? new ?Class[]? {?Method. class ?} );
45 ???????????? // 反射執(zhí)行start方法
46 ????????????start.invoke( this .proxy,? new ?Object[]? {?method?} );
47 ???????????? // 執(zhí)行要處理對(duì)象的原本方法
48 ????????????result?=?method.invoke( this .delegate,?args);
49 // ????????????反射得到操作者的end方法
50 ????????????Method?end?=?clazz.getDeclaredMethod("end",
51 ???????????????????? new ?Class[]? {?Method. class ?} );
52 // ????????????反射執(zhí)行end方法
53 ????????????end.invoke( this .proxy,? new ?Object[]? {?method?} );
54
55 ????????}
? catch ?(Exception?e)? {
56 ????????????e.printStackTrace();
57 ????????}

58 ???????? return ?result;
59 ????}

60
61 }

62


然后我們把Test.java中的代碼改一下.測(cè)試一下:

package ?sinosoft.dj.aop.proxyaop;

public ? class ?Test? {
???? public ? static ? void ?main(String[]?args)? {
????????IHello?hello?=?(IHello) new ?DynaProxyHello().bind( new ?Hello(), new ?LoggerOperation());
????????hello.sayGoogBye("Double?J");
????????hello.sayHello("Double?J");
????????
????}

}

結(jié)果還是一樣的吧.

如果你想在每個(gè)方法之前加上日志記錄,而不在方法后加上日志記錄.你就把LoggerOperation類改成如下:

?1 package ?sinosoft.dj.aop.proxyaop;
?2
?3 import ?java.lang.reflect.Method;
?4
?5 public ? class ?LoggerOperation? implements ?IOperation? {
?6
?7 ???? public ? void ?end(Method?method)? {
?8 ???????? // Logger.logging(Level.DEBUGE,?method.getName()?+?"?Method?end? .");
?9 ????}

10
11 ???? public ? void ?start(Method?method)? {
12 ????????Logger.logging(Level.INFO,?method.getName()?+?"?Method?Start!");
13 ????}

14
15 }

16


運(yùn)行一下.你就會(huì)發(fā)現(xiàn),每個(gè)方法之后沒(méi)有記錄日志了. 這樣,我們就把代理者和操作者解藕了!

下面留一個(gè)問(wèn)題給大家,如果我們不想讓所有方法都被日志記錄,我們應(yīng)該怎么去解藕呢.?
我的想法是在代理對(duì)象的public Object invoke(Object proxy, Method method, Object[] args)方法里面加上個(gè)if(),對(duì)傳進(jìn)來(lái)的method的名字進(jìn)行判斷,判斷的條件存在XML里面.這樣我們就可以配置文件時(shí)行解藕了.如果有興趣的朋友可以把操作者,被代理者,都通過(guò)配置文件進(jìn)行配置 ,那么就可以寫一個(gè)簡(jiǎn)單的SpringAOP框架了.

?

?

轉(zhuǎn): http://www.blogjava.net/DoubleJ/archive/2008/03/04/183796.html

?

更多: Java編程中使用動(dòng)態(tài)代理實(shí)現(xiàn)AOP功能? ? http://developer.51cto.com/art/200906/130539.htm ?

轉(zhuǎn):反射實(shí)現(xiàn) AOP 動(dòng)態(tài)代理模式(Spring AOP的實(shí)現(xiàn)原理)


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 那曲县| 长丰县| 清水河县| 呈贡县| 城步| 台湾省| 都江堰市| 顺平县| 高雄市| 和顺县| 丘北县| 济阳县| 南雄市| 泾源县| 光山县| 从化市| 潼关县| 诸暨市| 景泰县| 桦甸市| 怀来县| 平泉县| 无锡市| 关岭| 綦江县| 常熟市| 齐河县| 彭山县| 红河县| 连云港市| 巴东县| 庐江县| 荣成市| 繁峙县| 阳春市| 武威市| 岳西县| 八宿县| 太白县| 麻城市| 开阳县|