好長(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代碼如下:

?2

?3

?4

?5

?6

?7

?8

?9

10

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










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

?2

?3

?4

?5

?6

?7

?8

?9

10

11


12

13

14

15

16

17

18

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

?2

?3

?4

?5

?6

?7

?8

?9

10

11

12

13

14

15

16

17

18

19

20

21

Level.java

2

3

4

5

6

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

2

3

4

5

6

7

8

9

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




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

2

3

4

5

6

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

?2

?3

?4

?5

?6

?7

?8

?9

10

11

12

13

14

15

Hello.java?

?2

?3

?4

?5

?6

?7

?8

?9

10

11

12

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

?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

30

31

32

33

34

35

36


37

38

39

40

41

42

43

44

45

46

47

48

49

50

上面類中出現(xiàn)的Logger類和Level枚舉還是和上一上例子的實(shí)現(xiàn)是一樣的.這里就不貼出代碼了.
讓我們寫一個(gè)Test類去測(cè)試一下.代碼如下:
Test.java

?2

?3

?4

?5

?6

?7

?8

?9

10

11

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








由于線程的關(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 .接口定義如下 :

?2

?3

?4

?5

?6

?7

?8

?9

10

11

12

13

14

15

16

17

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

















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

?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

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

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











結(jié)果還是一樣的吧.
如果你想在每個(gè)方法之前加上日志記錄,而不在方法后加上日志記錄.你就把LoggerOperation類改成如下:

?2

?3

?4

?5

?6

?7

?8


?9

10

11

12

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ì)您有幫助就好】元
