Java动态代理

Java动态代理类位于java.lang.reflect包下,主要包括java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler
Proxy提供了创建动态代理类和动态代理实例的静态方法,是通过这些方法创建出来的所有代理类的超类。

代理接口是被代理类实现的接口。
代理实例是代理类的一个实例,需要实现代理接口和完成调用转发,可以在调用转发前或调用转发后执行一些附加逻辑。

Proxy中比较重要的方法有:

  • getProxyClass

    1
    public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)

    返回实现所有接口interfaces的代理类,该类由类加载器loader定义,且实现了interfaces中所有的接口。
    只要有任意一个接口是非public的,代理类便是非public的。
    如果相同接口的代理类已经被类加载器定义过了,则直接返回,否则由类加载器loader动态生成并定义该代理类。
    返回的动态代理类型为$Proxy开头的类,可能为$Proxy0,$Proxy1…,因为是动态生成的。

  • newProxyInstance

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

    返回实现接口interfaces的代理类实例,该实例对应的调用处理器为h,其定义的类加载器为loader。
    等价于通过getProxyClass创建代理类,然后通过反射并根据参数h构造动态代理类对象。

  • isProxyClass

    1
    2
    3
    public static boolean isProxyClass(Class<?> cl) {
    return Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
    }

    当且仅当cl是由getProxyClass或newProxyInstance动态生成的代理类返回true。

  • getInvocationHandler

    1
    public static InvocationHandler getInvocationHandler(Object proxy)

    返回对应的调用处理器

通过getProxyClass获得的代理类都包含一个构造函数,该构造函数需要一个InvocationHandler的实例,所以在newProxyInstance中还需要一个InvocationHandler的参数。

可以通过以下方法创建实现代理接口Foo的代理实例:

1
2
3
InvocationHandler handler = new MyInvocationHandler(...);//调用处理器
Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);//获取代理接口对应的动态代理类
Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).newInstance(handler);//反射创建代理实例

或者简单的调用newProxyInstance方法:

1
2
3
4
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class<?>[] { Foo.class }, handler);
```

动态代理上调用接口的方法时,会将该方法转发给相应的调用处理器InvocationHandler,InvocationHandler如下:

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

1
2
3
包含一个方法`invoke`。  
参数`proxy`为代理对象本身。
`method`为调用的代理对象的方法。`Method`为反射中的方法类型,含有invoke方法

public Object invoke(Object obj, Object… args)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
`` 这里obj为调用的对象,args为传入的方法参数。method.invoke(obj,args)等价于obj.method(args)。args`传递给该方法的参数。
而invoke的返回值作为代理对象方法的调用结果返回给用户。