Proxy
代码: java.lang.reflect.Proxy
Proxy提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。
构造一个新的Proxy实例,并指定调用处理器 InvocationHandler。
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
InvocationHandler
InvocationHandler 经常和 Proxy 配合使用。
InvocationHandler是由代理实例的调用处理程序实现的接口。
每个代理实例都有一个关联的调用处理程序。当在代理实例上调用方法时,方法调用会被编码并分派给其调用处理程序的 invoke 方法。
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
Proxy 和 InvocationHandler 代码示例
可以通过一个简单的示例, 了解下 Proxy 和 InvocationHandler 的使用。
- MyInterface :
public interface MyInterface {
String doSomething();
}
- MyInterfaceImpl :
public class MyInterfaceImpl implements MyInterface {
@Override
public String doSomething() {
System.out.println("MyInterfaceImpl doSomething");
return "doSomething result";
}
}
- MyInvocationHandler:
public class MyInvocationHandler implements InvocationHandler {
/**
* 目标对象
*/
private final Object target;
/**
* 调用处理器的构造方法,以目标对象作为参数
* @param target
*/
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//以下是一个简单的 AOP
//前置处理
System.out.println("before doSomething.");
//反射,调用目标对象的方法
Object result = method.invoke(target, args);
//后置处理
System.out.println("after doSomething.");
return result;
}
}
- ProxyDemo 示例:
public class ProxyDemo {
public static void main(String[] args) throws Exception {
//保存代理产生的类文件,方便查看 com.sun.proxy.$Proxy0 的源码
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
//被代理的目标对象
MyInterface myInterfaceImpl = new MyInterfaceImpl();
//自定义调用处理器 InvocationHandler , 以目标对象为参数
InvocationHandler invocationHandler = new MyInvocationHandler(myInterfaceImpl);
//Jdk动态代理支持的 Class对象必须是一个接口,否则会报错 IllegalArgumentException:is not an interface
MyInterface myInterface = (MyInterface) Proxy.newProxyInstance(
MyInterface.class.getClassLoader(),
new Class<?>[] { MyInterface.class },
invocationHandler);
//调用的实际是动态代理生成的 com.sun.proxy.$Proxy0 对象的 doSomething()方法
myInterface.doSomething();
}
}
源码 com.sun.proxy.$Proxy0
com.sun.proxy.Proxy0 继承了Proxy类,并实现了示例代码中的 MyInterface。
示例中加入以下代码,会保存代理产生的类文件,方便查看 com.sun.proxy.Proxy0 的源码。
//保存代理产生的类文件,方便查看 com.sun.proxy.$Proxy0 的源码
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
为什么调用代理对象的方法,就会调用自定义的 MyInvocationHandler 中的 invoke()方法?
可以看一下 com.sun.proxy.$Proxy0的源码。运行示例代码后,会自动生成这个类。
实际上调用的是父类Proxy的 InvocationHandler h 的 invoke()方法。
也就是示例代码中的 MyInvocationHandler类的 invoke() 方法。
public final class $Proxy0 extends Proxy implements MyInterface {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
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 doSomething() throws {
try {
//为什么调用代理对象的方法,就会调用自定义的 MyInvocationHandler 中的 invoke()方法
//实际上调用的是父类Proxy的 InvocationHandler h 的 invoke()方法。
//也就是示例代码中的 MyInvocationHandler类的 invoke() 方法。
return (String)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
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 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"));
// 这个m3,就是要被代理的目标接口 MyInterface 的 doSomething方法
m3 = Class.forName("com.example.demo.sourceCode.proxy.MyInterface").getMethod("doSomething");
m2 = Class.forName("java.lang.Object").getMethod("toString");
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
源码: java.lang.reflect.Proxy#newProxyInstance
newProxyInstance() 是代理类经常用的方法。
newProxyInstance() 方法返回指定接口的代理类实例,该代理类将方法调用分派给指定的调用处理程序(InvocationHandler)。
newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
第一个参数是类加载器ClassLoader。
第二个参数是将生成的动态代理对象挂在哪些接口下,这个参数可以设为真实对象所实现的接口。也正是因为这个参数,使用Jdk动态代理的对象必须拥有一个实现的接口,这是jdk动态代理的不足之处。
第三个参数是定义实现逻辑方法的调用处理器。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* 查找或生成指定的代理类。
*/
Class<?> cl = getProxyClass0(loader, intfs);
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
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;
}
});
}
//使用指定的调用处理程序(InvocationHandler)调用其构造函数。
//Constructor构造方法的 newInstance() 是支持 InvocationHandler转换为 Object 作为参数的。
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);
}
}
Jdk 动态代理的缺点
Jdk 动态代理 只支持接口级别的动态代理, 如果提供的不是接口,就会报错:
java.lang.IllegalArgumentException: is not an interface
源码:java.lang.reflect.Proxy.ProxyClassFactory#apply
//验证Class对象是否实际表示接口。如果不是接口,就会报错。
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
标签:Jdk,Object,代理,public,InvocationHandler,Proxy,new,源码
From: https://www.cnblogs.com/expiator/p/18446430