搜尋
首頁JavaJava基礎什麼是java代理

什麼是java代理

Nov 13, 2019 am 11:37 AM
java代理商

什麼是java代理

什麼是java代理   

什麼是代理呢,其實很好理解,就是不直接存取目標,而是透過一個中間層來訪問,就好像下面這樣:

什麼是java代理

#Java的靜態代理

舉個例子,如果我們一些水果,例如:香蕉、蘋果等,寫成Java程式碼,大概是下面這個樣子:(推薦教學:java教學 )

//Fruit.java/**
 * 水果的接口
 */public interface Fruit {    /**
     * 获取水果的名字
     */
    public String getName();
}//Apple.javapublic class Apple implements Fruit {    @Override
    public String getName() {        return "苹果";
    }
}//Banana.javapublic class Banana implements Fruit {    @Override
    public String getName() {        return "香蕉";
    }
}

吃水果,你要削皮吧,你不能每個水果都寫一個子類,類處理削皮這個事情吧。因此,我們可以做一個代理 ,吃蘋果之前,先把它削皮。就像下面這樣,把原來的水果包一層:

//PeelFruitProxy.java/**
 * 代理,让每个水果去皮
 */public class PeelFruitProxy implements Fruit {    private Fruit mFruit;    public PeelFruit(Fruit fruit) {        this.mFruit = fruit;
    }    @Override
    public String getName() {
        System.out.println("proxt:" + proxy.getClass().getName());        return "去皮的" + mFruit.getName();
    }
}

添加了測試類,測試類如下:

//Main.javapublic class Main {    public static void main(String[] args) {
        Apple apple=new Apple();//原始的苹果
        Banana banana=new Banana();//原始的香蕉

        PeelFruitProxy peelApple=new PeelFruitProxy(apple);//代理,添加去皮功能
        PeelFruitProxy peelBanana=new PeelFruitProxy(banana);//代理,添加去皮功能
        System.out.println(peelApple.getName());
        System.out.println(peelBanana.getName());
    }
}

以上就是Java的靜態代理,簡單點說,就是把原來的目標物件包一層,加入新東西再去呼叫目標本身。但是如果只是這樣的靜態代理,一個接口,就需要一個代理,實作起來是不是很繁瑣。

Java的動態代理

在Java中,有一個乾這個事情的類,叫做Proxy,可以直接使用反射方式,代理攔截。先簡單的介紹一下這個類,其實最常用的只有一個靜態方法Proxt.newProxyInstance(),是這樣的:

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

首先我們要實作InvocationHandler,實作其中的invoke方法,在呼叫目標物件的時候,會先呼叫到invoke方法,需要實作者在這個方法中,在主動呼叫被呼叫者方法。

//FruitInvocationHandler.java/**
 * 调用方法拦截器
 */public class FruitInvocationHandler implements InvocationHandler {    private Fruit mFruit;    public FruitInvocationHandler(Fruit fruit) {        this.mFruit = fruit;
    }    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String result = (String) method.invoke(mFruit, args);//需要在这个方法里面,主动调用被代理的对象。
        return "去皮的" + result;
    }
}

運行一下:

//Main.Javapublic class Main {    public static void main(String[] args) {
        Apple apple = new Apple();
        Fruit proxyApple = (Fruit) Proxy.newProxyInstance(Fruit.class.getClassLoader(), new Class[]{Fruit.class}, new FruitInvocationHandler(apple));
        System.out.println(proxyApple.getClass().getName());
        System.out.println(proxyApple.getName());

        Banana banana = new Banana();
        Fruit proxyBanana = (Fruit) Proxy.newProxyInstance(Fruit.class.getClassLoader(), new Class[]{Fruit.class}, new FruitInvocationHandler(banana));
        System.out.println(proxyApple.getClass().getName());
        System.out.println(proxyBanana.getName());
    }
}

什麼是java代理

這個方法,就是產生一個上文中的PeelFruitProxy(當然,我們看到的他名字叫:com.sun .proxy.$Proxy0),動態的生成,避免每次都需要寫,這個也是叫他動態代理的原因,因為我們可以在運行時代理任意類別。很多程式中的AOP就是這樣實現的,但是我們發現一些特點,newProxyInstance()的第二個參數,是一個interfaces的列表,為啥要有這個這個列表呢?

因為我們動態產生的代理類,也需要實作接口,這樣才方便向下轉型,使用其中的方法,不然,產生的類,類名就是com.sun.proxy.$Proxy0這種,並且是在記憶體中,無法呼叫產生的方法。 ** 所以,這種動態代理的方法,有一個致命的缺點,那就是被代理的類,必須要實作介面。 **

CGLib代理

cglib is a powerful, high performance and quality Code Generation Library, It is used to extend JAVA classes and implements interfaces at runtime.

另一個大名鼎鼎的Java代理實現,就是CGLib(Code Generation Library),一個基於ASM的程式碼產生框架,可以用他來動態生成類,然後實現對方法的攔截,就可以避開JDK的動態代理, 必須要目標類實現接口的問題了。也就是說,可以用CGLib來產生上文的PeelFruitProxy。

簡單介紹一下怎麼用,首先這個CGLib是一個三方的函式庫,我們要把它依賴進來:

compile 'cglib:cglib:3.2.8'

#最新版本可以在這裡看(新版本)[https://github.com/cglib/cglib/releases] 然後我們來試一試,我們來實現一下上面的代理

//FruitMethodInterceptor.java/**
 * CGLib代理的方法拦截器
 */public class FruitMethodInterceptor implements MethodInterceptor{    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        String result = (String) proxy.invokeSuper(obj, args);//主要,这里调用的是父类,也就是说, 生成的类和原始类是继承关系
        return "去皮的"+result;
    }
}//Main.javapublic class Main {    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Apple.class);
        enhancer.setCallback(new FruitMethodInterceptor());
        Apple apple = (Apple) enhancer.create();
        System.out.println(apple.getClass().getName());
        System.out.println(apple.getName());
    }
}

運行效果如下:

什麼是java代理

我們看到,實作了同樣的功能,但是,Apple已經不是原來的Apple類別了,變成了com.zjiecode.learn.java. proxy.Apple$$EnhancerByCGLIB$$44ade224,沒錯,我們正真使用的是這個類,而不是原來的Apple了,這個類繼承自Apple,最後實現了對Apple類的代理。這種方式,因為使用的是繼承,所以,不需要被代理的類別實作介面。當然,他也可以透過介面來實現代理。

總結

第一種代理,就不說了,只適合單一的一個介面的代理,在編譯時就決定好了。

第二、三種代理,都是動態時代理,但是我們看到也有差異:

1)JDK的動態代理,只能實現介面代理,並且是包裝的被代理對象(類的實例),也就是說,在代理的過程中,有2個對象,一個代理對象,一個目標對象,目標對像被包裝在代理對象裡面。

2)CGLib的代理,是繼承目標對象,生成了一個新的類,然後來實現代理,這樣,在內存中就是有代理對象,沒有目標對象了,使用的是直接繼承的方式

產生代理類別是在執行時,有別於javapoet在編譯時產生類別。

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

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

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具