JDK动态代理原理解析
一、例子:
1、定义基础接口
public interface HttpApi {
String get(String url);
}
2、实现类
public class RealModule implements HttpApi {
@Override
public String get(String url) {
return "result";
}
}
3、动态代理
public class ProxyFactory {
public static HttpApi getProxy(HttpApi target) {
return (HttpApi) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new LogHandler(target));
}
// 增强类
private static class LogHandler implements InvocationHandler {
private HttpApi target;
LogHandler(HttpApi target) {
this.target = target;
}
// method底层的方法无参数时,args为空或者长度为0
@Override
public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// 扩展的功能
Log.i("http-statistic", (String) args[0]);
// 访问基础对象
return method.invoke(target, args);
}
}
}
上面例子中出现的核心方法有:
- Proxy.newProxyInstance( target.getClass().getClassLoader(),target.getClass().getInterfaces(),new LogHandler(target));
- 参数说明:1.类加载器。2.指定newProxyInstance()方法返回的对象要实现哪些接口,可以指定多个接口。3.调用处理器,实现了InvocationHandler接口的实现类,重写invoke方法来增强被代理类的方法。
- 方法返回:实现了指定接口的实现类对象,即被代理类。
- invoke(Object proxy, Method method, @Nullable Object[] args) ;
- 参数说明:1.代理对象,也就是Proxy.newProxyInstance()方法返回的对象。2.被代理对象的方法如例子中的get()方法。3.表示当前被调用方法的参数。
- 方法返回:前被调用的方法的返回值,没有返回值则返回null。
二、反编译代理类源码
public final class $proxy0 extends Proxy implements HttpApi {
//反射的元数据Method存储起来,避免重复创建
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $proxy0(InvocationHandler var1) throws {
super(var1);
}
/**
* Object#hashCode()
* Object#equals(Object)
* Object#toString()
*/
// 实现了HttpApi接口
public final String get() throws {
try {
//转发到Invocation#invoke()
return (String)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
//Object#hashCode()
//Object#equals(Object)
//Object#toString()
m3 = Class.forName("HttpApi").getMethod("get");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
通过反编译的源码我们可以得到以下结论:
- JDK动态代理生成了代理类(继承Proxy)的字节码文件(Class)。
- 代理类继承自 java.lang.reflect.Proxy,实现了HttpApi接口。
- 代理类中的所有方法都是final 的。
- 代理类所有的方法功能的实现都统一调用了InvocationHandler的invoke()方法。
- 通过(String)super.h.invoke(this, m3, (Object[])null)方法进入增强类以实现对被代理方法的增强。
- JDK动态代理只能对实现了接口的类进行代理,不能对普通类进行代理,这是因为JDK动态代理生成的新的代理类其父类是Proxy,java不支持类的多继承,所以只能实现接口。
三、核心类Proxy源码解析
1.JDK动态代理核心类:Proxy。
2.Proxy主要API
方法 | 描述 |
getProxyClass(ClassLoader, Class<?>...) : Class<?> | 获取实现目标接口的代理类 Class 对象 |
newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h): Object | 获取实现目标接口的代理对象 |
isProxyClass(Class<?>) : boolean | 判断一个 Class 对象是否属于代理类 |
getInvocationHandler(Object) : InvocationHandler | 获取代理对象内部的 InvocationHandler |
3.核心源码:
3.1 Proxy.java
1、获取代理类 Class 对象
public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces){
final Class<?>[] intfs = interfaces.clone();
...
1.1 获得代理类 Class 对象
return getProxyClass0(loader, intfs);
}
2、实例化代理类对象
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h){
...
final Class<?>[] intfs = interfaces.clone();
2.1 获得代理类 Class对象
Class<?> cl = getProxyClass0(loader, intfs);
...
2.2 获得代理类构造器 (接收一个 InvocationHandler 参数)
// private static final Class<?>[] constructorParams = { InvocationHandler.class };
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
...
2.3 反射创建实例
return newInstance(cons, ih);
}
可以看到,实例化代理对象也需要先通过 getProxyClass0(...) 获取代理类 Class 对象,