黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

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

系統(tǒng) 2192 0

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

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

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

10


里面有個方法,用于輸入"Hello" 加傳進(jìn)來的姓名;我們?nèi)憘€類實現(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)在我們要為這個業(yè)務(wù)方法加上日志記錄的業(yè)務(wù),我們在不改變原代碼的情況下,我們會去怎么做呢?也許,你會去寫一個類去實現(xiàn)IHello接口,并依賴Hello這個類.代碼如下:

?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ù)等級記錄日志
?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)憘€測試類看看,代碼如下:
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

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

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


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

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


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

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


我們一樣的去寫一個代理類.只不過.讓這個類去實現(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 ?????*?要處理的對象(也就是我們要在方法的前后加上業(yè)務(wù)邏輯的對象,如例子中的Hello)
11 ????? */

12 ???? private ?Object?delegate;
13
14 ???? /**
15 ?????*?動態(tài)生成方法被處理過后的對象?(寫法固定)
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 ?????*?要處理的對象中的每個方法會被此方法送去JVM調(diào)用,也就是說,要處理的對象的方法只能通過此方法調(diào)用
29 ?????*?此方法是動態(tài)的,不是手動調(diào)用的
30 ????? */

31 ???? public ?Object?invoke(Object?proxy,?Method?method,?Object[]?args)
32 ???????????? throws ?Throwable? {
33 ????????Object?result?=? null ;
34 ???????? try ? {
35 ???????????? // 執(zhí)行原來的方法之前記錄日志
36 ????????????Logger.logging(Level.DEBUGE,?method.getName()?+?"?Method?end? .");
37 ????????????
38 ???????????? // JVM通過這條語句執(zhí)行原來的方法(反射機(jī)制)
39 ????????????result?=?method.invoke( this .delegate,?args);
40 ???????????? // 執(zhí)行原來的方法之后記錄日志
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枚舉還是和上一上例子的實現(xiàn)是一樣的.這里就不貼出代碼了.

讓我們寫一個Test類去測試一下.代碼如下:
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


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


}


然后我們要改一下代理對象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 ?????*?要處理的對象(也就是我們要在方法的前后加上業(yè)務(wù)邏輯的對象,如例子中的Hello)
14 ????? */

15 ???? private ?Object?delegate;
16
17 ???? /**
18 ?????*?動態(tài)生成方法被處理過后的對象?(寫法固定)
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 ?????*?要處理的對象中的每個方法會被此方法送去JVM調(diào)用,也就是說,要處理的對象的方法只能通過此方法調(diào)用
34 ?????*?此方法是動態(tài)的,不是手動調(diào)用的
35 ????? */

36 ???? public ?Object?invoke(Object?proxy,?Method?method,?Object[]?args)
37 ???????????? throws ?Throwable? {
38 ????????Object?result?=? null ;
39 ???????? try ? {
40 ???????????? // 反射得到操作者的實例
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í)行要處理對象的原本方法
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中的代碼改一下.測試一下:

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é)果還是一樣的吧.

如果你想在每個方法之前加上日志記錄,而不在方法后加上日志記錄.你就把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


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

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

?

?

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

?

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

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


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

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

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

【本文對您有幫助就好】

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

發(fā)表我的評論
最新評論 總共0條評論