聊聊、动态代理
动态代理大家都不陌生,生活中也有很多动态代理的例子,例如:香港代购。我们只需要说产品名称,代购就可以把产品从香港买回来给我们。
微服务特别火,基本上每个公司都会涉及到。微服务的调用却是离不开 RPC 框架,从 RMI、WEBSERVICE、到今天的 Dubbo、GRPC、Thrift、SpringCloud等等。我们调用远程服务就像是调用本地服务一样,其实这些 RPC 框架给我们做了很多的事情,这些事情对我们来说是透明的。而代理技术,就是这些事情的核心功能。
JDK动态代理
JDK动态代理是 JDK 反射机制实现的,首先实现 InvocationHandler 接口
1.InvocationHandler
package org.jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class JDKProxyInvoker implements InvocationHandler {
private Object object;
public JDKProxyInvoker(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("===invoke before===");
Object result = method.invoke(object, args);
System.out.println("===invoke after===");
return result;
}
}
2.IUser.java
package org.PO;
public interface IUser {
public String sayHello();
}
3.UserImpl.java
package org.PO;
public class UserImpl implements IUser {
@Override
public String sayHello() {
System.out.println("===sayHello===");
return "UserImpl hello";
}
}
4.Main
IUser iUser = (IUser) Proxy.newProxyInstance(M.class.getClassLoader(),new Class[]{IUser.class},new JDKProxyInvoker(new UserImpl()));
System.out.println(iUser.sayHello());
5.结果
6.Proxy.newProxyInstance原理
byte[] b = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{IUser.class});
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream("src/main/java/org/jdkproxy/$Proxy0.class");
outputStream.write(b);
outputStream.flush();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
7.$Proxy0.class
public final class $Proxy0 extends Proxy implements IUser {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("org.PO.IUser").getMethod("sayHello");
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());
}
}
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final void sayHello() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
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 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);
}
}
}
iUser.sayHello() 实质上调用的是 $Proxy0.sayHello() 也就是
public final void sayHello() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
这里其实有一个面试题,问 JDK动态代理为什么是代理接口而不是类呢?public final class $Proxy0 extends Proxy implements IUser ,因为已经继承了 Proxy,而 Java 不能多继承。