今天上午刚刚写完Retrofit的源码解读.
写完以后思考了一下,发现了2个问题.
1.对于Proxy.newProxyInstance()这个动态代理还是一知半解.
2.Retrofit是如何将InterfaceService传入的值 传递给OkHttpCall进行网路网络请求的.
怀着这2个疑问,再学习研究一番.
对于动态代理的概念性的了解和相关的,可以参考一下Retrofit那篇,引用的动态代理博文.
对于Retrofit,我们都知道核心是这个,能够将InterfaceService class类通过动态代理获取到InterfaceService对象的这个过程.
点开Proxy.newProxyInstance()的源码,了解一下.
发现核心是这return的3个方法.
熟悉反射的一样就看出来了,这
getConstructor()和newInstance() 不就是反射创建对象么.
重点看一下getProxyClass这个方法.
这个方法传入的是对应的classLoader和这个InterfaceService.class
根据传入的参数关键字interfaces(即InterfaceService.class),查找它是如何被动态代理的.
通过观察这个源码,我们发现了几个信息.
Class > result = generateProxy(name, interfaces, loader, methodsArray, exceptionsArray);
研究一下这个"generateProxy()".
发现已经是个Native方法了.
GG,不过总体来说,我们已经知道了InterfaceService的动态代理类是通过底层C来实现的,然后通过反射生成对应的接口对象.
源码里面看到的终究是猜测,实际上,还是得验证一下才行.
同时也学习一下如何真正的使用动态代理和获取注解信息.
主方法:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final User userProxy = getProxy(User.class);
//验证一下动态的代理生成的类名
System.out.println("尝试验证一下动态代理类的类名:" + userProxy.getClass().getName());
//手动点击,获取Annotation
findViewById(R.id.clickNow).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (userProxy != null) {
userProxy.getUser("试试看啊");
}
}
});
}
@SuppressWarnings("unchecked")
private T getProxy(Class service) {
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
getAnnotation(method);
System.out.println("尝试获取Parms注解填入的值:" + objects[0]);
return null;
}
});
}
/**
* 模仿Retrofit获取注解信息和参数注解的值.
*/
private void getAnnotation(Method method) {
//分别获取方法的注解名,属性注解类型,属性注解名
Annotation[] annotations = method.getAnnotations();
Type[] parmsTypeAnnotations = method.getGenericParameterTypes();
Annotation[][] parmsAnnotations = method.getParameterAnnotations();
if (annotations.length > 0) {
System.out.println("尝试获取Test注解信息:" + annotations[0]);
}
if (parmsTypeAnnotations.length > 0 && parmsAnnotations.length > 0) {
System.out.println("尝试获取Parms注解名称:" + parmsTypeAnnotations[0]);
System.out.println("尝试获取Parms注解内容的key:" + parmsAnnotations[0][0]);
}
}
}
InterfaceService:
public interface User {
@Test
void getUser(@Parms("okok") String ojbk);
}
自定义的2个注解.
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@interface Parms {
String value();
}
通过这个简单的类…
动态代理获取User的接口对象 --> 调用getUser() --> 触发InvocationHandler的invoke() --> 获取注解信息.
相关注释已经尽量写了.
只能把原因归结于InterfaceService.getPackageName$()获取失败了,但是这个方法没有办法继续追踪了.
以后有机会再找找原因.
这也就解释了,Retrofit是如何将InterfaceService的方法值传递给OkHttpCall去执行网络请求的.
又是收获满满的一天…
咋感觉提出离职,主动走出舒适区后,这种紧迫感下每天的收获比之前多多了.