简介
jdk动态代理用于在运行时生成实现多个接口的动态代理类,关键的类有两个
Proxy:提供多个静态方法用于创建动态代理类和动态代理对象,同时也是所有此种方式生成的动态代理类的父类
InvocationHandler:该接口只有一个方法如下,每个动态代理对象都有一个关联的InvocationHandler实例对象,当一个动态代理对象的方法被调用时,实际上是被分配到了InvocationHandler实例对象的invoke方法
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
例子
Proxy中有两种代码方式生成动态代理对象(假设代理的接口为Foo):
//生成InvocationHandler对象
InvocationHandler handler = new MyInvocationHandler(...);
//方法1 生成代理类 再获得代理类的构造方法然后newInstance
Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
newInstance(handler);
//方法2 在方法里一步解决生成代理对象
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class<?>[] { Foo.class },
handler);
这里以第二种为例子
//接口Person
public interface Person {
public void say(String name);
}
//实现类Chinese
public class Chinese implements Person {
@Override
public void say(String name) {
System.out.println(name + "你好");
}
}
//测试类
public class Test {
public static void main(String[] args) throws Exception{
//设置系统参数保存生成的代理类到文件中,可以到项目根目录下com/sun/proxy目录中找到代理类class文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
final Person person = new Chinese();
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("test");
return method.invoke(person, args);
}
};
Person proxy = (Person) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class[]{Person.class},handler);
proxy.say("justin");
}
}
结果:test
justin你好
代码分析
为什么这样写,以及为什么能得到这样的结果可以通过看代理类class文件得到答案
//代理类实现代理接口继承Proxy类
public final class $Proxy0 extends Proxy implements Person {
//从后面的静态代码块可以看出这几个Method属性就是代理接口(以及Object类)中方法的反射对象
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
//参数为InvocationHandler的构造函数 用于生成代理对象,父类Proxy中该方法作用就是将var1赋值给属性InvocationHandler
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
//重写代理接口和Object方法,同时都改成final方法,方法内容都一致:
以生成的代理类、接口或Object类的方法反射对象、方法调用参数为参数调用父类Proxy中InvocationHandler属性h(也就是构造函数传入的var1)的invoke方法
上面的测试类Test中handler对象的invoke方法,第一句system.out.println("test")相当于功能增强,第二句return method.invoke(person,args);是实际上执行方法的语句
这里person是方法的实际调用者,代理类传过来的proxy一般不用。
对比直接用person调用差别只是功能增强的打印语句那一块
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void say(String var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.test.proxy.Person").getMethod("say", Class.forName("java.lang.String"));
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
生成代理类分析
Proxy的newProxyInstance方法内容如下:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
//保证参数h不为空
Objects.requireNonNull(h);
//克隆要代理的接口
final Class<?>[] intfs = interfaces.clone();
//安全管理
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
生成代理类class对象 这里会缓存到一个WeakCache中如果用相同的ClassLoader和接口生成过代理类那直接从这里取,如果没有则用二进制拼接出class内容,在加载到内存中
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//这里的constructorParams是{InvocationHandler.class} 获得参数类型为InvocationHandler的构造方法
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
//返回方法代理类实例
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}