Java Dynamic Proxy

- 4 mins

简介

Proxy 是设计模式中的一种。当需要在已存在的 class 上添加或修改功能时,可以通过创建 proxy object 来实现

通常 proxy object 和被代理对象拥有相同的方法,并且拥有被代理对象的引用,可以调用其方法

代理模式应用场景包括

代理有两种实现方式

对于重复性工作,如打印日志,静态代理需要为每个 class 都创建 proxy class,过程繁琐和低效,而动态代理通过使用反射在运行时生成 bytecode 的方式来实现,更加方便和强大

过程

因为 JDK 自带的 Dynamic proxy 只能够代理 interfaces,因此被代理对象需要实现一个或多个接口,具体可参考 https://stackoverflow.com/a/10664208

先来看一些概念:

InvocationHandler 接口的定义如下

package java.lang.reflect;

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

只定义了一个方法 invoke(),参数含义如下

简单来说就是,调用 proxy object 上的方法,最终都会转换成对关联 InvocationHandlerinvoke() 方法的调用

可以使用 java.lang.reflect.Proxy 的静态方法 newProxyInstance 来创建 Proxy object

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

参数说明

例子

使用动态代理打印方法的执行耗时

定义代理接口

public interface Foo {
    String doSomething();
}

实现接口

public class FooImpl implements Foo {
    @Override
    public String doSomething() {
        return "finished";
    }
}

定义 InvocationHandlertarget 为被代理对象的引用,在方法执行完后打印耗时

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

public class TimingInvocationHandler implements InvocationHandler {
    private Object target;

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

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        long start = System.nanoTime();
        Object result = method.invoke(target, args);
        long elapsed = System.nanoTime() - start;

        System.out.println(String.format("Executing %s finished in %d ns",
                method.getName(),
                elapsed));

        return result;
    }
}

测试

import org.junit.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class DynamicProxyTest {
    @Test
    public void test() {
        ClassLoader cl = DynamicProxyTest.class.getClassLoader();
        Class[] interfaces = new Class[]{Foo.class};
        FooImpl fooImpl = new FooImpl();
        InvocationHandler timingInvocationHandler = new TimingInvocationHandler(fooImpl);
        Foo foo = (Foo) Proxy.newProxyInstance(cl, interfaces, timingInvocationHandler);
        foo.doSomething();
    }
}

执行完会打印类似

Executing doSomething finished in 23148 ns

细节

生成 proxy class 的一些属性和细节

参考

b1ngz
rss facebook twitter github weibo youtube mail spotify instagram linkedin google pinterest medium vimeo