美文网首页android技术
30.Android架构-动态代理原理

30.Android架构-动态代理原理

作者: 任振铭 | 来源:发表于2020-09-05 08:17 被阅读0次

动态代理和静态代理的区别之一就是可以同时代理同一个对象的多个接口

public interface Husband {
    void careFamily();
}

public interface Father {
    void teachChild();
}


Man man = new Man();
Object o = Proxy.newProxyInstance(Man.class.getClassLoader(), new Class[]{Husband.class, Father.class}, new InvocationHandler() {
    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
         return method.invoke(man, objects);
    }
});

((Husband)o).careFamily();
((Father)o).teachChild();  

简单看下源码

可以看到,返回值是getProxyClass0方法得到的Class后,通过反射创建了这个Class的对象,那么getProxyClass0做了什么?

public static Object newProxyInstance(ClassLoader var0, Class<?>[] var1, InvocationHandler var2) throws IllegalArgumentException {
        ......
        Class var5 = getProxyClass0(var0, var3);

        try {
            ......

            final Constructor var6 = var5.getConstructor(constructorParams);
            ......

            return var6.newInstance(var2);
        } catch (Exception var10) {
            ......
        }
    }

可以看到是从一个WeakCache<ClassLoader, Class<?>[], Class<?>>取出来的,说明已经生成好了,生成的时机我们不去考虑

private static Class<?> getProxyClass0(ClassLoader var0, Class... var1) {
        if (var1.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        } else {
            return (Class)proxyClassCache.get(var0, var1);
        }
    }

private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache(new Proxy.KeyFactory(), new Proxy.ProxyClassFactory());

关键就是在ProxyClassFactory类中

Proxy.newProxyInstance 会创建一个Class,与静态代理不同,这个Class不是由具体的.java源文件编译
而来,即没有真正的文件,只是在内存中按照Class格式生成了一个Class。

在Proxy中有一个静态内部类:ProxyClassFactory,在他的apply方法中可以看到这样一行代码

String var23 = var16 + "$Proxy" + var19;
//第一参数表示类名,是拼装后的,第二个表示 Class<?>[] var1,代理接口数组
byte[] var22 = ProxyGenerator.generateProxyClass(var23, var2, var17);

通过这个方法会在内存中生成一个类的字节码数组,然后

Proxy.defineClass0(var1, var23, var22, 0, var22.length);

定义出这个类,内存中就有这个类了

模拟生成这个类

我们按照这种方式,将生成类写入文件可以看到类长什么样子

String name = Husband.class.getName() + "$Proxy0";
//生成代理指定接口的Class数据
byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{Husband.class});
FileOutputStream fos = new FileOutputStream("lib/" + name + ".class");
fos.write(bytes);
fos.close();

生成的类如下,可以看到,这个类继承自Proxy,实现了我们需要代理的接口,继承自Proxy,从前边的分析我们可以知道,Proxy.newProxyInstance返回的就是这个类的对象,所以他可以强转成我们的代理接口,因为实现自这个接口

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.enjoy.lib;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class Husband$Proxy0 extends Proxy implements Husband {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    //可以看到静态代码块中生成了四个方法,其中有三个equals toString hashCode是每个类自带的(Object)
    //careFamily是我们接口中提供的方法
    //类一生成就通过反射获取到了几个关键方法的method
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.enjoy.lib.Husband").getMethod("careFamily");
            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 Husband$Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    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 void careFamily() throws  {
        try {
            //当外界调用careFamilly方法的时候,会执行到这里,h就是传入的InvocationHandler
            //m3就是静态代码块中获取到的careFamily方法(来自接口),因为我们方法没有传参数,所以为null
            super.h.invoke(this, m3, (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);
        }
    }
}

所以看到这里我们大概可以知道动态代理的原理了,动态代理通过传入的代理接口在内存中生成一个代理对象,这个代理对象实现了我们传入接口的方法,如此一来,外部在拿到代理对象的时候就可以强转成对应的接口,调用相应的方法,调用方法后会执行代理对象中对应的方法,然后通过InvocationHandler的invoke方法将对应接口的对应方法的method和参数回调出来,然后再次使用反射,传入我们的实例对象,这样便达到了调用我们实例对象方法的目的

所以想象中高大上的动态代理不过如此!

Retrofit中的泛型 注解 和动态代理

我们只需要知道,Retrofit是对OkHttp的一层封装,本身他没有做网络请求的功能,他只是一层封装

使用Retrofit是从创建一个接口开始的

public interface WeatherApi {

    @POST("/v3/weather/weatherInfo")
    Call postWeather(@Field("city") String city, @Field("key") String key);


    @GET("/v3/weather/weatherInfo")
    Call getWeather(@Query("city") String city, @Query("key") String key);
}

在调用的时候

        Retrofit retrofit = new Retrofit.Builder().baseUrl("https://restapi.amap.com")
               .build();
        weatherApi = retrofit.create(WeatherApi.class);
        Call<ResponseBody> call = weatherApi.getWeather("110101", "ae6c53e2186f33bbf240a12d80672d1b");
        call.enqueue(new Callback<ResponseBody>() {...}

核心是在retrofit.create(WeatherApi.class)方法上,传入我们上边实现的接口class,拿到代理对象,没错,就是用到了动态代理

public <T> T create(final Class<T> service) {
    validateServiceInterface(service);
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();
          private final Object[] emptyArgs = new Object[0];

          @Override public @Nullable Object invoke(Object proxy, Method method,
              @Nullable 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);
            }
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

于是等通过代理对象调用getWeather方法的时候,就会进入到动态代理的invoke方法,在这里会进行一系列的处理,包括解析接口上的配置信息,解析接口方法的参数信息,最后拼成一个url,最后执行反射,拿到一个Okhttp的Call,就可以执行请求了

call.enqueue(new Callback<ResponseBody>() {...}

相关文章

  • 30.Android架构-动态代理原理

    动态代理和静态代理的区别之一就是可以同时代理同一个对象的多个接口 简单看下源码 可以看到,返回值是getProxy...

  • 设计模式~代理模式

    学习代理模式内容: ★ 静态代理、 ★ 动态代理(JDK动态代理、CGLIB动态代理)、 ★ 拦截器的原理和日志记...

  • Java动态代理从入门到原理再到实战

    目录 前言 什么是动态代理,和静态代理有什么区别 Java动态代理的简单使用 Java动态代理的原理解读 动态代理...

  • 代理模式

    1.概念 2.静态代理 3.动态代理 3.1 JDK 动态代理 原理 手工模拟JDK动态代理 3.2cglib动态...

  • AOP——cglib动态代理源码解析

    上一篇分析了使用JDK动态代理的低层实现原理,这次再来看看cglib实现动态代理的原理。 关于JDK动态代理的实现...

  • java动态代理

    本文从四个方面认识动态代理 什么是代理? 为什么使用代理? 如何使用动态代理? 动态代理的原理 一 什么是代理 ...

  • JDK动态代理实践与原理

    本篇内容 介绍JDK动态代理的基本概念 一些JDK动态代理的疑问 JDK动态代理的Demo JDK动态代理的原理 ...

  • java基础巩固笔记(4)-代理

    标签: java Contents java基础巩固笔记(4)-代理概念动态代理创建动态类动态代理的工作原理面向切...

  • 【Android架构师java原理专题详解】二;反射原理及动态代

    前言; 本篇为Android架构师java原理专题二;反射原理及动态代理模式。大公司面试都要求我们有扎实的Java...

  • 动态代理(二)

    动态代理的原理 我们可以看到动态代理是根据反射实现的,那么我们可以自己实现动态代理吗? 1、每个动态代理的类都实现...

网友评论

    本文标题:30.Android架构-动态代理原理

    本文链接:https://www.haomeiwen.com/subject/kgnasktx.html