JDK1.3以後,Java提供了動態代理的技術,容許開發者在運行期間建立接口的代理實例。java
1、首先咱們進行JDK動態代理的演示。node
如今咱們有一個簡單的業務接口Saying,以下:ide
package testAOP;
public interface Saying {
public void sayHello(String name);
public void talking(String name);
}
一個簡單的實現類SayingImpl,以下:測試
package testAOP; public class SayingImpl implements Saying { @Override public void sayHello(String name) { // TODO Auto-generated method stub System.out.println(name + ":你們好啊!"); } @Override public void talking(String name) { // TODO Auto-generated method stub System.out.println(name + ":個人意思是,咱們要努力建設和諧社會!"); } }
咱們要實現的是,在sayHello和talking以前和以後分別動態植入處理。this
JDK動態代理主要用到java.lang.reflect包中的兩個類:Proxy和InvocationHandler.spa
InvocationHandler是一個接口,經過實現該接口定義橫切邏輯,並經過反射機制調用目標類的代碼,動態的將橫切邏輯和業務邏輯編織在一塊兒。代理
Proxy利用InvocationHandler動態建立一個符合某一接口的實例,生成目標類的代理對象。code
以下,咱們建立一個InvocationHandler實例:對象
package testAOP; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler { private Object target; MyInvocationHandler(Object target){ this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //目標方法前執行 System.out.println("——————————————————————————"); System.out.println("下一位請登臺發言!"); //目標方法調用 Object obj = method.invoke(target, args); //目標方法後執行 System.out.println("你們掌聲鼓勵!"); return obj; } }
下面是測試:blog
package testAOP; import java.lang.reflect.Proxy; public class JDKProxyTest { public static void main(String[] args) { // 但願被代理的目標業務類 Saying target = new SayingImpl(); // 將目標類和橫切類編織在一塊兒 MyInvocationHandler handler = new MyInvocationHandler(target); // 建立代理實例 Saying proxy = (Saying) Proxy.newProxyInstance( target.getClass().getClassLoader(),//目標類的類加載器 target.getClass().getInterfaces(),//目標類的接口 handler);//橫切類 proxy.sayHello("小明"); proxy.talking("小麗"); } }
運行狀況以下:
——————————————————————————
下一位請登臺發言!
小明:你們好啊!
你們掌聲鼓勵!
——————————————————————————
下一位請登臺發言!
小麗:個人意思是,咱們要努力建設和諧社會!
你們掌聲鼓勵!
使用JDK動態代理有一個很大的限制,就是它要求目標類必須實現了對應方法的接口,它只能爲接口建立代理實例。咱們在上文測試類中的Proxy的newProxyInstance方法中能夠看到,該方法第二個參數即是目標類的接口。若是該類沒有實現接口,這就要靠cglib動態代理了。
CGLib採用很是底層的字節碼技術,能夠爲一個類建立一個子類,並在子類中採用方法攔截的技術攔截全部父類方法的調用,並順勢植入橫切邏輯。
2、接下來咱們進行cglib動態代理的演示。
首先咱們須要導包,我用的包是cglib-nodep-2.1_3.jar。
咱們首先建立一個代理建立器CglibProxy:
package testAOP.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CglibProxy implements MethodInterceptor{ Enhancer enhancer = new Enhancer(); public Object getProxy(Class clazz) { //設置須要建立的子類 enhancer.setSuperclass(clazz); enhancer.setCallback(this); //經過字節碼技術動態建立子類實例 return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // TODO Auto-generated method stub System.out.println("——————————————————————————"); System.out.println("下一位請登臺發言!"); //目標方法調用 Object result = proxy.invokeSuper(obj, args); //目標方法後執行 System.out.println("你們掌聲鼓勵!"); return result; } }
而後進行測試:
package testAOP.cglib; import testAOP.Saying; import testAOP.SayingImpl; public class CglibProxyTest { public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); //經過動態生成子類的方式建立代理類 Saying target = (Saying) proxy.getProxy(SayingImpl.class); target.sayHello("小明"); target.talking("小麗"); } }
結果與JDK動態代理沒有任何區別。
CGLib動態代理能代理類和接口,可是不能代理final類,也是有必定侷限性。
JDK動態代理和CGLib動態代理都是運行時加強,經過將橫切代碼植入代理類的方式加強。與此不一樣的是AspectJ,它可以在經過特殊的編譯器在編譯時期將橫切代碼植入加強,這樣的加強處理在運行時候更有優點,由於JDK動態代理和CGLib動態代理每次運行都須要加強。