前言
面试中经常被问到动态代理相关内容,每次都答得不够完美,又因近期在尝试手写RPC框架,了解到不少的动态代理相关的内容,顺道总结一下,于是就有了这篇文章
静态代理? 动态代理!
区别
静态代理是在编译期间就生成了实际的字节码和对应的class文件,而动态代理可以在运行中动态生成代理类。
- 静态代理示例
public interface Service {
void perform();
}
// 实际类
public class RealService implements Service {
@Override
public void perform() {
System.out.println("Performing service...");
}
}
// 代理类也要实现和被代理的类实现的同一个接口才能进行代理
public class StaticProxy implements Service {
// 将需要代理的类封装到自己的内部
private final Service realService;
public StaticProxy(Service realService) {
this.realService = realService;
}
// 实际就是在实现的方法中进行代理操作,然后执行被代理的类的方法
@Override
public void perform() {
System.out.println("Static Proxy: Before performing service");
realService.perform();
System.out.println("Static Proxy: After performing service");
}
}
实际上就是通过将被代理类封装到内部,然后调用。缺点很明显:没新增一个代理都需要重新新建一个类然后重新写一个包装。
- 动态代理实例(JDK代理)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public interface Service {
void perform();
}
public class RealService implements Service {
@Override
public void perform() {
System.out.println("Performing service...");
}
}
public class DynamicProxyHandler implements InvocationHandler {
private final Object target;
public DynamicProxyHandler(Object target) {
this.target = target;
}
//
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Dynamic Proxy: Before performing service");
Object result = method.invoke(target, args);
System.out.println("Dynamic Proxy: After performing service");
return result;
}
}
public class DynamicProxyDemo {
public static void main(String[] args) {
Service realService = new RealService();
Service proxyInstance = (Service) Proxy.newProxyInstance(
realService.getClass().getClassLoader(),
realService.getClass().getInterfaces(),
new DynamicProxyHandler(realService)
);
proxyInstance.perform();
}
}
源码解读
解密Proxy
(以下是基于Java8的源码)
我们在使用JDK动态代理的时候使用的最多的就是Proxy.newProxyInstance()方法,接下来我们就来解密这个方法是如何实现我们的动态代理。
@CallerSensitive
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);
/*
* Invoke its constructor with the designated invocation handler.
*/
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;
}
});
}
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);
}
}
参数解析:
- loader:类加载器,用于自定义加载类
- interface 接口数组,代理类将实现这些接口
- h 调用处理器,处理代理实例上的方法调用 这段代码的主要意思是获取调用者类和代理类构造函数。 接着关注getProxyClass0方法
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
// 规定对实现的接口数量不得超过这个数量
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}
接着看proxyClassCache
// 使用WeakCache降低出现内存泄漏的概率
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
核心是ProxyClassFactroy,让我们关注它
// 核心是实现BiFunction
/**
* ProxyClassFactory 是一个工厂类,用于生成和定义代理类。
* 它实现了 BiFunction 接口,接受 ClassLoader 和接口数组作为输入,
* 返回生成的代理类。
*/
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
// 所有代理类名称的前缀
private static final String proxyClassNamePrefix = "$Proxy";
// 用于生成唯一代理类名称的下一个数字
private static final AtomicLong nextUniqueNumber = new AtomicLong();
/**
* 生成并定义代理类。
*
* @param loader 用于定义代理类的��加载器
* @param interfaces 代理类要实现的接口数组
* @return 生成的代理类
* @throws IllegalArgumentException 如果接口数组中的任何接口不可见或不是接口,或接口重复
*/
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
// 使用 IdentityHashMap 检查接口是否重复
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
/*
* 验证类加载器是否将此接口的名称解析为相同的 Class 对象。
*/
Class<?> interfaceClass = null;
try {
// 对于每一个使用指定的加载器去加载他的对象
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader: " + loader);
}
/*
* 验证 Class 对象是否实际代表一个接口。
*/
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* 验证此接口是否重复。
*/
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null; // 定义代理类的包
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
* 记录非公共代理接口的包,以便代理类将在同一包中定义。
* 验证所有非公共代理接口是否在同一包中。
*/
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// 如果没有非公共代理接口,使用 com.sun.proxy 包
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* 选择要生成的代理类的名称。
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* 生成指定的代理类。
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
* 这里的 ClassFormatError 意味着(除非代理类生成代码中有错误),
* 否则是代理类创建时提供的参数存在其他无效方面(例如虚拟机限制超出)。
*/
throw new IllegalArgumentException(e.toString());
}
}
}
BiFunction 是 Java 8 引入的一个函数式接口,位于 java.util.function 包中。它代表一个接受两个输入参数并返回一个结果的函数。BiFunction 接口定义如下:
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u);
// 其他默认方法
}
然后我们顺着往下找,通过generateProxyClass ->generateClassFile ->generateMethod 代码过长这里只给出比较重要的部分
{
// 获取InvocationHandler字段
out.writeByte(opc_getfield);
out.writeShort(cp.getFieldRef(
superclassName,
handlerFieldName, "Ljava/lang/reflect/InvocationHandler;"));
// 加载Method对象
code_aload(0, out);
out.writeByte(opc_getstatic);
out.writeShort(cp.getFieldRef(
dotToSlash(className),
methodFieldName, "Ljava/lang/reflect/Method;"));
// 后面紧跟处理方法参数的部分,这部分省略
// 重点!
// 调用InvocationHandler.invoke方法
out.writeByte(opc_invokeinterface);
out.writeShort(cp.getInterfaceMethodRef(
"java/lang/reflect/InvocationHandler",
"invoke",
"(Ljava/lang/Object;Ljava/lang/reflect/Method;" +
"[Ljava/lang/Object;)Ljava/lang/Object;"));
out.writeByte(4);
out.writeByte(0);
// 后面设置返回值和异常处理等信息,最后返回方法的信息
return minfo;
}
到这里我们才终于发现JDK动态代理的原理: 原来就是在代理方法中通过Proxy引用了自定义的InvocationHandler!! 通过Proxy.newProxyInstance()方法将invocationHandler传入,然后生成代理类来继承Proxy类,从而拿到InvocationHandler,最后在代理类中调用invoke()方法