首頁 >Java >java教程 >java什麼是代理?

java什麼是代理?

青灯夜游
青灯夜游原創
2019-11-18 17:17:153988瀏覽

java什麼是代理?

java什麼是代理?

代理程式是一種設計模式,提供了對目標物件另外的存取方式,即透過代理物件存取目標物件。可以不修改目標對象,對目標對像功能進行拓展。

代理程式的作用:降低程式碼的冗餘。

代理模式的實現分為兩大類:靜態實現和動態實現,動態實現根據實現的方式分為:jdk 動態實現,cglib動態實現

Java的三種代理模式

想要實現以上的需求有三種方式,這一部分我們只看三種模式的程式碼怎麼寫,先不涉及實作原理的部分。

1、靜態代理程式

public interface ISinger {
    void sing();
}

/**
 *  目标对象实现了某一接口
 */
public class Singer implements ISinger{
    public void sing(){
        System.out.println("唱一首歌");
    }  
}

/**
 *  代理对象和目标对象实现相同的接口
 */
public class SingerProxy implements ISinger{
    // 接收目标对象,以便调用sing方法
    private ISinger target;
    public UserDaoProxy(ISinger target){
        this.target=target;
    }
    // 对目标对象的sing方法进行功能扩展
    public void sing() {
        System.out.println("向观众问好");
        target.sing();
        System.out.println("谢谢大家");
    }
}

測試

/**
 * 测试类
 */
public class Test {
    public static void main(String[] args) {
        //目标对象
        ISinger target = new Singer();
        //代理对象
        ISinger proxy = new SingerProxy(target);
        //执行的是代理的方法
        proxy.sing();
    }
}

優點: 做到不修改目標物件的功能前提下,對目標功能擴展

缺點:這種實作方式很直覺也很簡單,但其缺點是代理物件必須事先寫出,如果介面層發生了變化,代理物件的程式碼也要進行維護。如果能在運行時動態地寫出代理對象,不但減少了一大批代理類的程式碼,也少了不斷維護的煩惱,不過運行時的效率必定受到影響。這種方式就是接下來的動態代理。

2、JDK代理

跟靜態代理的前提一樣,依然是對Singer物件進行擴展

public interface ISinger {
    void sing();
}

/**
 *  目标对象实现了某一接口
 */
public class Singer implements ISinger{
    public void sing(){
        System.out.println("唱一首歌");
    }  
}

這回直接上測試,由於java底層封裝了實作細節(之後會詳細講),所以程式碼非常簡單,格式基本上也固定。

呼叫Proxy類別的靜態方法newProxyInstance即可,此方法會傳回代理類別物件

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )

接收的三個參數依序為:

 ● ClassLoader loader:指定目前目標物件使用類別載入器,寫法固定

 ● Class6b3d0130bba23ae47fe2b8e8cddf0195[] interfaces:目標物件實現的介面的類型,寫法固定

 ● InvocationHandler h:事件處理接口,需傳入一個實作類,一般直接使用匿名內部類別

測試程式碼

public class Test{
    public static void main(String[] args) {
  Singer target = new Singer();
        ISinger proxy  = (ISinger) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("向观众问好");
                        //执行目标对象方法
                        Object returnValue = method.invoke(target, args);
                        System.out.println("谢谢大家");
                        return returnValue;
                    }
                });
        proxy.sing();
    }
}

優點:動態實作了不改變目標物件邏輯的擴展

缺點:可以看出靜態代理和JDK代理有一個共同的缺點,就是目標物件必須實現一個或多個接口,不然無法實現動態代理。

3、Cglib代理

前提條件:

 ● 需要引入cglib的jar文件,由於Spring的核心包中已經包括了Cglib功能,所以也可以直接引入spring-core-3.2.5.jar

 ● 目標類別不能為final

 ● 目標物件的方法如果為final/static,那麼就不會被攔截,即不會執行目標物件額外的業務方法

/**
 * 目标对象,没有实现任何接口
 */
public class Singer{

    public void sing() {
        System.out.println("唱一首歌");
    }
}
/**
 * Cglib子类代理工厂
 */
public class ProxyFactory implements MethodInterceptor{
    // 维护目标对象
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    // 给目标对象创建一个代理对象
    public Object getProxyInstance(){
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("向观众问好");
        //执行目标对象的方法
        Object returnValue = method.invoke(target, args);
        System.out.println("谢谢大家");
        return returnValue;
    }
}

這裡的程式碼也非常固定,只有標黃部分是需要自己寫出

測試

/**
 * 测试类
 */
public class Test{
    public static void main(String[] args){
        //目标对象
        Singer target = new Singer();
        //代理对象
        Singer proxy = (Singer)new ProxyFactory(target).getProxyInstance();
        //执行代理对象的方法
        proxy.sing();
    }
}

優點:動態實作了不改變目標物件邏輯的擴展

缺點:目標必須實現接口,不然無法實現動態代理

總結:三種代理模式各有優缺點和相應的適用範圍,主要看目標對像是否實現了接口。以Spring框架所選的代理模式舉例

在Spring的AOP編程中:
如果加入容器的目標對像有實現接口,用JDK代理
如果目標對象沒有實現接口,用Cglib代理

以上是java什麼是代理?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn