Java使用Porxy和InvocationHandler實現動態代理

weixin_33912246發表於2017-06-06

代理模式:通過代理間接的呼叫被代理物件的方法,結構如下:

426671-0b7e322eb8777825.png
image.png

Java的反射包提供了一個Porxy類和InvokationHandler介面。它們結合在一起後可以建立動態代理類。Porxy類基於傳遞的引數建立動態代理類。InvokationHandler則用於激發動態代理類的方法。這個過程是在程式執行過程中動態生成與處理的,所以叫動態代理。分析一下

Porxy類

Porxy類提供了一個靜態方法建立動態代理類。

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

1、ClassLoader:ClassLoader會定義動態代理類,ClassLoader可以通過類或者介面獲得,如果我們想通過介面獲得,呼叫方法如下。

    Task.class.getClassLoader()

如果通過類來獲得,加入我們有一個類TaskImpl實現了Task介面,我們有個TaskImpl的物件ob,然後ClassLoader獲取方法如下

    ob.getClassLoader()

2、 Class<?>[] interfaces:動態代理類需要實現的介面
3、InvocationHandler:傳遞一個實現了InvokationHandler介面的類的例項

InvokationHandler

InvokationHandler是Java 反射包裡面的一個介面。InvokationHandler通過使用者類來實現,來激發一個動態代理類的方法。它只有一個方法:

public Object invoke(Object proxy, Method method, Object[] args)    throws Throwable;

1、Object:實現方法的代理物件
2、Method:代理例項激發的方法,Porxy引數中的介面方法
3、Object[]:傳遞給方法的一系列引數

實現

1、我們提供一個介面

package me.aihe;

public interface Task {
    void setData(String data);
    int getCalData(int x);
}

2、實現這個介面

package me.aihe;

public class TaskImpl implements Task {
    @Override
    public void setData(String data) {
        System.out.println(data+ " Data is saved");
    }

    @Override
    public int getCalData(int x) {
        return x * 10;
    }
}

3、定義自己的InvokationHandler類,並且實現InvokationHandler介面的Invoke方法

package me.aihe;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MyInvokationHandler implements InvocationHandler {

    private Object obj;
    public MyInvokationHandler(Object object){
        this.obj = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result;
        if(method.getName().contains("get")){
            System.out.println("...get Method Executing...");
        }else{
            System.out.println("...set Method Executing...");
        }
        result = method.invoke(obj, args);
        return result;
    }
}

4、建立一個工廠類獲取動態代理類:

package me.aihe;

import java.lang.reflect.Proxy;

public class ProxyFactory {
    public static Object newInstance(Object ob) {
        return Proxy.newProxyInstance(ob.getClass().getClassLoader(),
                new Class<?>[] { Task.class }, new MyInvokationHandler(ob));
    }
}

5、提供我們的測試類

package me.aihe;

public class Test {

    public static void main(String[] args) {
        Task task = (Task)ProxyFactory.newInstance(new TaskImpl());
        task.setData("Test");
        System.out.println("============");
        System.out.println(task.getCalData(5));
    }
}

看到程式的輸出結果:

...set Method Executing...
Test Data is saved
============
...get Method Executing...
50

總結

動態代理的實現流程:
1、建立一個介面
2、提供一個實現這個介面的類
3、建立一個實現了InvokationHandler介面的類,實現Invoke方法。
傳遞引數:實現介面的類
4、可選:建立一個代理工廠。
返回值傳遞引數:ClassLoader,實現的介面,實現介面的類

參考:

相關文章