国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

深入淺析Spring 的aop實現原理

2019-11-26 14:27:56
字體:
來源:轉載
供稿:網友

什么是AOP

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

簡介

  前段時間寫的java設計模式--代理模式,最近在看Spring Aop的時候,覺得于代理模式應該有密切的聯系,于是決定了解下Spring Aop的實現原理。

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

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

實現原理  

  前面在學習代理模式的時候,了解到代理模式分為動態代理和靜態代理。現在我們就以代理模式為基礎先實現我們自己的AOP框架,再來研究Spring的AOP的實現原理。

  先以靜態代理實現,靜態代理關鍵是在代理對象和目標對象實現共同的接口,并且代理對象持有目標對象的引用。

  公共接口代碼:

public interface IHello {/*** 業務方法* @param str*/void sayHello(String str);}   目標類代碼:public class Hello implements IHello{@Overridepublic void sayHello(String str) {System.out.println("hello "+str);}} 

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

public class ProxyHello implements IHello{ private IHello hello; public ProxyHello(IHello hello) {super();this.hello = hello;}@Overridepublic void sayHello(String str) {Logger.start();//添加特定的方法hello.sayHello(str);Logger.end();}}

  日志類代碼:

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");}}

  測試代碼:

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

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

  動態代理實現主要是實現InvocationHandler,并且將目標對象注入到代理對象中,利用反射機制來執行目標對象的方法。

  接口實現與靜態代理相同,代理類代碼:

public class DynaProxyHello implements InvocationHandler{private Object target;//目標對象/*** 通過反射來實例化目標對象* @param object* @return*/public Object bind(Object object){this.target = object;return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {Object result = null;Logger.start();//添加額外的方法//通過反射機制來運行目標對象的方法result = method.invoke(this.target, args);Logger.end();return result;}}

  測試類代碼:

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

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

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

  我們要在被代理對象的方法前面或者后面去加上日志操作代碼(或者是其它操作的代碼),那么,我們可以抽象出一個接口,這個接口里就只有兩個方法:一個是在被代理對象要執行方法之前執行的方法,我們取名為start,第二個方法就是在被代理對象執行方法之后執行的方法,我們取名為end。

  Logger的接口:

public interface ILogger {void start(Method method);void end(Method method);}

  Logger的接口實現:

public class DLogger implements ILogger{@Overridepublic void start(Method method) {System.out.println(new Date()+ method.getName() + " say hello start...");}@Overridepublic void end(Method method) {System.out.println(new Date()+ method.getName() + " say hello end");}}

 動態代理類:

public class DynaProxyHello implements InvocationHandler{//調用對象private Object proxy;//目標對象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);}@Overridepublic 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});//反射執行start方法start.invoke(this.proxy, new Object[]{this.proxy.getClass()});//執行要處理對象的原本方法method.invoke(this.target, args);//反射得到操作者的end方法Method end = clazz.getDeclaredMethod("end", new Class[]{Method.class});//反射執行end方法end.invoke(this.proxy, new Object[]{method});return result;}} 

  測試代碼:

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

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

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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 交口县| 巨野县| 元江| 阳西县| 大姚县| 扎赉特旗| 凤山市| 平安县| 屏东市| 龙岩市| 北票市| 贡觉县| 阳西县| 青州市| 冀州市| 海淀区| 万年县| 嵊州市| 肇东市| 安图县| 柯坪县| 镇安县| 合山市| 南昌县| 衡水市| 合水县| 娱乐| 武陟县| 白朗县| 泊头市| 凯里市| 资讯 | 大名县| 安丘市| 通许县| 同心县| 阿瓦提县| 竹溪县| 葵青区| 犍为县| 内丘县|