AOP從本質上講是在咱們可視以外改變了程序的運行軌跡,比方說,有個方法method執行完,就結束了,經過AOP在method前插入N個操做、在method後插入N個操做,那麼這時要執行method方法,須要執行前面的N個操做才能進入,要退出,還得把後面的N個操做走完。java
AOP適合須要織入共性操做的場景,如:全部模塊都須要事務控制,那麼就經過AOP的方式把事務控制的邏輯織入到每一個模塊的方法裏。AOP有三種織入操做,即前置加強、後置加強、環繞加強,環繞加強不一樣於前置後置,它能夠決定是否執行被代理方法,改變目標方法的返回值。git
談到織入額外操做,不得不談代理模式。代理者再代理被代理者時,能夠作其餘額外操做,例如:祕書是老闆的代理,公司要求客戶必須先和祕書通電話確認有預定才能和老闆通電話。ide
代碼以下:工具
public interface Phone { public void listen(); } public class Boss implements Phone { @Override public void listen() { System.out.println("我是老闆"); } } public class Secretary implements Phone { private Boss boss; public Secretary() { } public Secretary(Boss boss) { this.boss = boss; } @Override public void listen() { System.out.println("已經預定"); boss.listen(); } }
代理模式包括三種角色:this
一、抽象主題:定義被代理者和代理者共用的接口,也就是上例的Phone接口;.net
二、實際主題:實現抽象主題接口的類,就是上例的Boss類設計
三、代理(Proxy):也實現了抽象主題接口,也存放了實際主題的引用,能夠控制對被代理對象的訪問。代理
用代理模式能夠織入一些額外操做,如上例的老闆接電話前,是經過祕書確認是否預定過的,但是這種模式是靜態的,每一個被代理類都要寫一個代理類,很是麻煩。接下來看怎麼解決這個問題。code
JDK提供一種動態代理的機制,動態代理本質上是在運行期動態生成代理的java字節碼,這樣就能夠代理多個類了,那麼咱們看用動態代理怎麼代理Boss這個打電話操做,對象
一、經過實現InvocationHandler接口來自定義本身的InvocationHandler;
二、Proxy.newProxyInstance來獲取代理類
public class JDKDynamicProxyTest { public static void main(String[] args) { Boss boss = new Boss(); InvocationHandler invocationHandler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("已經預定"); Object result = method.invoke(boss, args); return result; } }; Phone proxy = (Phone) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), boss.getClass().getInterfaces(), invocationHandler);//獲取代理對象 proxy.listen(); } }
這樣子作的好處顯而易見,對於共性業務能夠定義一個InvocationHandler,用Proxy.newProxyInstance獲取每一個類的代理對象,是否是很省事呢?這裏全靠動態生成Java字節碼,只有是怎麼動態生成的,這裏就不討論了。
這樣又會有新的問題,JDK自帶動態代理只能代理有實現了接口的類,那麼沒有接口的類怎麼被代理呢?這讓我把目光轉向了ASM和Cglib,ASM是一個字節碼生成工具,須要對JVM內部結構包括class文件的格式和指令集都很熟悉,開發效率比較低、難度比較大。Cglib底層雖然依賴於ASM,可是作了不少封裝,使用方便,因爲cglib生成的代理類是繼承與被代理類的,全部被代理類中若是有final方法,是不能被代理的。接下來看看怎麼經過cglib來代理老闆接電話。
定義了一個MethodInterceptor,用來攔截被代理類中要執行的方法。
public class CglibProxyTest { public static void main(String[] args) { Phone proxy = (Phone) Enhancer.create(Boss.class, new MethodInterceptor() { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("已經預定"); return proxy.invokeSuper(obj, args); } }); proxy.listen(); } }
自此,咱們解決了大部分問題,能夠用cglib來實現AOP了,但是cglib不能嵌套代理,也就是被代理的類,不能再次被cglib代理,當要往一個類中織入多個操做邏輯時,又該怎麼實現呢?
這些問題將在《TeaFramework——AOP的設計與實現》中講到。
項目地址:https://git.oschina.net/lxkm/teaframework
博客:https://my.oschina.net/u/1778239/blog