Java动态代理类位于java.lang.reflect
包下,主要包括java.lang.reflect.Proxy
和java.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
3public 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
3InvocationHandler 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
4Foo 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的返回值作为代理对象方法的调用结果返回给用户。