JDK動態代理和CGLib動態代理簡單演示

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動態代理每次運行都須要加強。

相關文章
相關標籤/搜索