动态代理基础
动态代理是在程序运行时动态创建一个代理类,实现的过程和静态代理一致,只是它是由反射实现的, 是AOP的基础
动态代理类不会继承被代理类的接口,而是实现InvocationHandler
,例如:
1 | class OwnerInvocationHandler implements InvocationHandler { |
我们关注的就只是invoke方法和被传入的被代理对象personBean
创建代理类实例
1 | PersonBean person = new PersonBeanImpl(); |
可以看到代理类是用反射实现的
当然,也可以把创建过程写到动态代理类中
1 | public static PersonBean newProxyInstance(PersonBean person){ |
Retrofit
中动态类的实现
撇开动态代理模式不谈,可以看到,Proxy可以生成生成一个继承特定接口的类,而一个继承了该接口的实现类也不是必要的。
这时联想到Retrofit
,它也是使用Proxy
生成的
1 | public interface GitHub { |
1 | Retrofit retrofit = new Retrofit.Builder() |
retrofit.create
的实现1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
通过retrofit.create
创建的对象,在执行相应的方法时都会经过这个内部类的invoke
方法,再通过ServiceMethod
进行相关的请求。
其实仔细想就明白了,每个网络请求其实并不关心叫什么名子,它只需要知道请求的url和参数就可以接着进行统一的网络请求就可以,所以看起来我们在定义接口的时候每个请求都定义了一个方法,但实际上这些方法没必要每个都实现。
而这个ServiceMethod
内部不用看就知道肯定是会通过method
来读取每个接口上的注解,以便知道该进行什么样的网络请求
动态代理类实现原理分析:
可以看到,通过Proxy.newProxyInstance
生成了一个继承通用接口的实例,调用它的方法时就会调用动态代理类InvocationHandler
的invoke
方法,那么这个类是实现的呢
1 | public static Object newProxyInstance(ClassLoader loader, |
通过cl.getConstructor(constructorParams)
可以看到创建的动态类是有构造方法是传入了InvocationHandler
的
生成这个类是应该是在getProxyClass0
里面
1 | private static final WeakCache<ClassLoader, Class<?>[], Class<?>> |
proxyClassCache
很明显只是一个缓存用的对象,正直生成的地方应该就是ProxyClassFactory
这个ProxyClassFactory
内部收集完必要的信息后调用一个native
方法生成并加载到内存的
根据网上的资料,可以通过以下方法把这个类给弄出来
1 | byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", PersonBean.class.getInterfaces()); |