Java中的代理的使用

jopen 10年前發布 | 14K 次閱讀 Java Java開發

Java中的代理

代理解釋:一種設計模式,代理類與委托類(被代理對象、目標對象)有同樣的接口,代理類主要負責為委托類預處理消息、過濾消息、把消息轉發給委托類,以及事后處理消息等。代理類與委托類之間通常會存在關聯關系,一個代理類的對象與一個委托類的對象關聯,代理類的對象本身并不真正實現服務,而是通過調用委托類的對象的相關方法,來提供特定的服務。 

通俗解釋:不直接調運目標對象,直接調運代理對象,讓代理對象去調運目標對象。

代理目的:當調運代理對象,然后在代理對象調運目標對象之前或者調運目標對象以后,我們可以干一些事,比如權限控制,日志記錄等。

代理分類:靜態代理,動態代理

舉例分析:

    程序說明:有剛學說話的個小朋友想說“我是中國人”,但是他不能完整的說出來,只能說“中國”兩個字,那么我們就使用代理模式,讓他的爸爸媽媽幫他把他想說的話補充完整。他的爸爸幫他說:“我是”,他的媽媽幫他說:“人”。然后即使小朋友只說了“中國”,但是我們聽見的就是“我是中國人”。

    這其中小朋友就是被代理對象、目標對象,他的爸爸媽媽就是代理對象。

    首先建立一個Person接口:

public interface Person {
    public void say();
}

    建立一個接口的實現類:

public class PersonImpl implements Person {
    @Override
    public void say() {
        System.out.print("中國");
    }
}

    再建立一個沒有實現接口的類:

public class PersonNoImpl {
    public void say() {
        System.out.print("中華人民共和國");
    }
}

 

    1.靜態代理:在程序運行前,代理類的.class文件就已經存在了。

public class PersonProxy implements Person {
    private Person person;// 被代理對象

    public PersonProxy(Person p) {         this.person = p;     }

    @Override     public void say() {         System.out.print("我是-");         person.say();// 在目標方法前后分別添加操作         System.out.println("-人");     }

}</pre>

    這種方式的最大缺點就是每次我們都需要建立不同的代理對象,靈活性和可復用性都很差,所以我們需要使用到動態代理技術。

 

    2.動態代理:在程序運行時,運用反射機制動態創建而成。

        有兩種實現方式:JDK代理,CGLIB代理

        方式1:使用jdk提供的代理對象(代理對象需要實現InvocationHandler接口,目標對象必須實現其他接口)

public class PersonProxyJdk implements InvocationHandler {
    private Object targetObj;

    /             @param obj                  被代理對象       @return 代理對象的實例      */     public Object createProxyInstance(Object obj) {         this.targetObj = obj;         /           參數說明 參數一:ClassLoader,定義代理類的類加載器           參數二:Class<?>,代理類要實現的接口列表          * 參數三:InvocationHandler,指派方法調用的調用處理程序 (指定調運哪個類的invoke方法)          **/         return Proxy.newProxyInstance(obj.getClass().getClassLoader(), this.targetObj.getClass().getInterfaces(), this);     }

    /       當代理對象的方法被調運時,就會執行回調函數invoke方法,讓這個回調函數再去執行目標代碼的指定方法,       并且會將代理對象接收到的參數傳遞給目標代碼。 這是一個回調函數。       注意:method args 都是由調運代理對象后產生的。所以是確定的。       還可以在這個回調函數中做一些手腳,比如限制調運或者其他。      /     @Override     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {         Object result = null;         System.out.print("我是");         result = method.invoke(targetObj, args);         System.out.println("人");         return result;     }

}</pre>

            注意:目標對象必須實現接口。因為需要得到接口的所有方法,然后進行調運接口的所有方法。

        方式2:使用cglib提供的代理對象(代理對象需要實現MethodInterceptor接口,目標對象不需要實現接口)

//導包:cglib-nodep-2.2.3.jar
public class PersonProxyCglib implements MethodInterceptor {
    private Object targetObj;

    /*       生成的代理對象其實就是目標對象的子類       @param obj                  被代理對象       @return 代理對象的實例      /     public Object createProxyInstance(Object obj) {         this.targetObj = obj;         Enhancer enhancer = new Enhancer();// 用于生成代理對象         enhancer.setSuperclass(this.targetObj.getClass());// 設置代理對象的父類         enhancer.setCallback(this);// 設置代理對象的回調函數就是本身         return enhancer.create();// 生成代理對象     }

    /       當代理對象的方法被調運時,就會執行改代理對象的回調函數,也就是intercept方法 這個回調函數接收代理對象傳遞來的參數      */     @Override     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {         Object result = null;         System.out.print("我是#");         result = proxy.invokeSuper(obj, args);         System.out.print("#人");         return result;     }

}</pre>

            注意:目標對象不須實現接口。因為生成的代理對象時目標對象的子類。

 

    3.測試上面的代理

public class Main {
    public static void main(String[] args) {

        Person zhangsan = new PersonImpl();// 被代理的對象

        zhangsan.say();// 如果讓代理目標直接執行目標方法,就不能在目標方法前后操作         System.out.println();

        PersonProxy proxy = new PersonProxy(zhangsan);// 將被代理的對象傳遞一個代理類         proxy.say();// 讓代理類去執行目標方法,這個時候代理類就在目標方法執行前后亂搞了

        PersonProxyJdk proxyJdk = new PersonProxyJdk();// 創建一個代理對象         Person zhangsanJdk = (Person) proxyJdk.createProxyInstance(zhangsan);// 將被代理對象傳遞給代理對象,并且返回被代理接口         zhangsanJdk.say();// 調運被代理對象的接口,就能動態的去執行代理對象想要執行的操作

        PersonProxyCglib proxyCglib = new PersonProxyCglib();// 創建Cglib代理對象         Person zhansanCglib = (Person) proxyCglib.createProxyInstance(zhangsan);// 將被代理對象傳遞給代理對象,并且返回被代理接口         zhansanCglib.say();// 調運被代理對象的接口,就能動態的去執行代理對象想要執行的操作                  // 使用Cglib的時候,目標對象可以不實現任何接口,但是使用JDK代理的時候就不可以         PersonNoImpl lisi = new PersonNoImpl();         PersonNoImpl lisiCglib = (PersonNoImpl) proxyCglib.createProxyInstance(lisi);         lisiCglib.say();

    } } 輸出: 中國 我是-中國-人 我是中國人 我是#中國#人 我是#中華人民共和國#人</pre>來自:http://dyygusi.iteye.com/blog/1994843

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!