46、設計模式之動態代理模式

代理模式分爲兩種,靜態代理 和 動態代理,靜態代理簡單易懂,對於新手來說便於理解,但實際運用到項目中代碼量以及維護量都是非常大的,在企業級項目中不推薦使用這種方式,用於學習或者做畢設還是可以的,本文中只闡述動態代理模式,記錄在這用於加深自身理解,同時希望能對您有所幫助。

JDK 動態代理

這種方式,只能對實現了接口的類生成代理,JDK動態代理採用委託機制,動態實現接口類,在動態生成的實現類中委託hanlder去調用原始實現類方法,但對於沒有實現接口的類來說,就不適用了

/**
 * 接口
 */
public interface Person {
    void say();
}
/**
 * 實現類
 * 對於JDK 動態代理來說,只有 實現了接口的類纔可以使用這種代理方式
 */
public class Children implements Person {
    @Override
    public void say() {
        System.out.println("你好,世界。");
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * JDK 動態代理
 */
public class JDKProxy implements InvocationHandler {

    private Object targetObject;

    public Object newProxy(Object targetObject){
        this.targetObject = targetObject;
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
            targetObject.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("練習發音");
        // 這裏切勿 使用 proxy 傳參變量,會報錯喲
        // 在newProxy 方法 接收的參數targetObject,目的是在這裏被運用
        Object result = method.invoke(targetObject, args);
        System.out.println("恭喜成功");
        return result;
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Main {

    public static void main(String[] args) {

        Person person = (Person) new JDKProxy().newProxy(new Children());
        person.say();

        // 報錯信息:Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to Children
        // 	at Main.main(Main.java:12)
        // JDK 動態代理,動態生成的實現類 和 Children 並無關係,所以這裏強轉會報錯
        // 這種方式,採用委託機制,在動態生成的實現類裏,委託Handler去調用原始實現類中的方法
        /*
        Children children = (Children) new JDKProxy().newProxy(new Children());
        children.say();
        */


    }
}

CGlib 動態代理

這種方式,不限制類是否實現了接口,相對於JDK 動態代理改進不少,同時又比JDK動態代理具備更高效的執行效率。

/**
 * 沒有實現接口的類,用於Cglib 動態代理
 */
public class User {

    public void shopping(){
        System.out.println("去海吉星採購");
    }
}

 

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor {

    private Object targetObject;

    public Object newProxy(Object targetObject){
        this.targetObject = targetObject;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetObject.getClass());
        enhancer.setCallback(this);
        Object object = enhancer.create();
        return object;
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("開始處理……");
        Object result = method.invoke(targetObject, args);
        System.out.println("結束活動");
        return result;
    }
}

public class Main {

    public static void main(String[] args) {
        User user = (User) new CglibProxy().newProxy(new User());
        user.shopping();
    }
}

Cglib方式,上面的代碼如要運行成功,還需 額外引入 cglib-2.2.jar 和 asm-3.1jar,這兩個包,特別注意的事,cglib-3.1.jar,引入會報錯,由於時間關係,沒有特別深入的瞭解原因,換成 2.2版本即可

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章