溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

java中的代理是什么

發(fā)布時間:2020-06-26 12:14:30 來源:億速云 閱讀:158 作者:Leah 欄目:編程語言

java中的代理是什么?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

代理是一種設(shè)計模式,提供了對目標對象另外的訪問方式,即通過代理對象訪問目標對象。可以不修改目標對象,對目標對象功能進行拓展。

代理的作用:降低代碼的冗余。

代理模式的實現(xiàn)分為兩大類:靜態(tài)實現(xiàn)和動態(tài)實現(xiàn),動態(tài)實現(xiàn)根據(jù)實現(xiàn)的方式分為:jdk 動態(tài)實現(xiàn),cglib動態(tài)實現(xiàn)

Java的三種代理模式

想要實現(xiàn)以上的需求有三種方式,這一部分我們只看三種模式的代碼怎么寫,先不涉及實現(xiàn)原理的部分。

1、靜態(tài)代理

public interface ISinger {
    void sing();
}

/**
 *  目標對象實現(xiàn)了某一接口
 */
public class Singer implements ISinger{
    public void sing(){
        System.out.println("唱一首歌");
    }  
}

/**
 *  代理對象和目標對象實現(xiàn)相同的接口
 */
public class SingerProxy implements ISinger{
    // 接收目標對象,以便調(diào)用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);
        //執(zhí)行的是代理的方法
        proxy.sing();
    }
}

優(yōu)點: 做到不修改目標對象的功能前提下,對目標功能擴展

缺點:這種實現(xiàn)方式很直觀也很簡單,但其缺點是代理對象必須提前寫出,如果接口層發(fā)生了變化,代理對象的代碼也要進行維護。如果能在運行時動態(tài)地寫出代理對象,不但減少了一大批代理類的代碼,也少了不斷維護的煩惱,不過運行時的效率必定受到影響。這種方式就是接下來的動態(tài)代理。

2、JDK代理

跟靜態(tài)代理的前提一樣,依然是對Singer對象進行擴展

public interface ISinger {
    void sing();
}

/**
 *  目標對象實現(xiàn)了某一接口
 */
public class Singer implements ISinger{
    public void sing(){
        System.out.println("唱一首歌");
    }  
}

這回直接上測試,由于java底層封裝了實現(xiàn)細節(jié)(之后會詳細講),所以代碼非常簡單,格式也基本上固定。

調(diào)用Proxy類的靜態(tài)方法newProxyInstance即可,該方法會返回代理類對象

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

接收的三個參數(shù)依次為:

 ● ClassLoader loader:指定當前目標對象使用類加載器,寫法固定

 ● Class<?>[] interfaces:目標對象實現(xiàn)的接口的類型,寫法固定

 ● InvocationHandler h:事件處理接口,需傳入一個實現(xiàn)類,一般直接使用匿名內(nèi)部類

測試代碼

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("向觀眾問好");
                        //執(zhí)行目標對象方法
                        Object returnValue = method.invoke(target, args);
                        System.out.println("謝謝大家");
                        return returnValue;
                    }
                });
        proxy.sing();
    }
}

優(yōu)點:動態(tài)實現(xiàn)了不改變目標對象邏輯的擴展

缺點:可以看出靜態(tài)代理和JDK代理有一個共同的缺點,就是目標對象必須實現(xiàn)一個或多個接口,不然無法實現(xiàn)動態(tài)代理。

3、Cglib代理

前提條件:

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

 ● 目標類不能為final

 ● 目標對象的方法如果為final/static,那么就不會被攔截,即不會執(zhí)行目標對象額外的業(yè)務(wù)方法

/**
 * 目標對象,沒有實現(xiàn)任何接口
 */
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;
    }

    // 給目標對象創(chuàng)建一個代理對象
    public Object getProxyInstance(){
        //1.工具類
        Enhancer en = new Enhancer();
        //2.設(shè)置父類
        en.setSuperclass(target.getClass());
        //3.設(shè)置回調(diào)函數(shù)
        en.setCallback(this);
        //4.創(chuàng)建子類(代理對象)
        return en.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("向觀眾問好");
        //執(zhí)行目標對象的方法
        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();
        //執(zhí)行代理對象的方法
        proxy.sing();
    }
}

優(yōu)點:動態(tài)實現(xiàn)了不改變目標對象邏輯的擴展

缺點:目標必須實現(xiàn)接口,不然無法實現(xiàn)動態(tài)代理

總結(jié):三種代理模式各有優(yōu)缺點和相應(yīng)的適用范圍,主要看目標對象是否實現(xiàn)了接口。以Spring框架所選擇的代理模式舉例

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

看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進一步的了解或閱讀更多相關(guān)文章,請關(guān)注億速云行業(yè)資訊頻道,感謝您對億速云的支持。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI