美文网首页
jdk动态代理和retrofit

jdk动态代理和retrofit

作者: 勇敢地追 | 来源:发表于2019-09-28 16:29 被阅读0次

1.静态代理

比如说本人要买华为手机,可以自己买,也可以让别人帮着买

public interface Buyer {
    void buy();
}

public class Me implements Buyer {
    @Override
    public void buy() {
        System.out.println("I want to buy HUAWEI");
    }
}

现在本人比较忙,所以决定让姐姐帮我代购(当然,也可以是其他人)

public class BuyProxy implements Buyer {
    private Buyer mBuyer;
    public BuyProxy(Buyer buyer) {
        mBuyer = buyer;
    }
    @Override
    public void buy() {
        System.out.println("I am BuyProxy");
        mBuyer.buy();
    }
}

以上,就是常见的静态代理模式
由此可见,静态代理其实就是代理一类行为
那如果下次不是代购,而是代课了呢?(这里只是举个例子)

2.动态代理

我们为代课进行了如下的实现

public interface TakeLesson {
    void take();
}
public class Me implements Buyer, TakeLesson {
    @Override
    public void buy() {
        System.out.println("I want to buy HUAWEI");
    }
    //新增这个接口的实现
    @Override
    public void take() {
        System.out.println("I want someone to have Math class. I will give 50 yuan");
    }
}
public class TakeLessonProxy implements TakeLesson {
    
    private TakeLesson mTaker;
    
    public TakeLessonProxy(TakeLesson taker) {
        mTaker = taker;
    }

    @Override
    public void take() {
        System.out.println("This is TakeLessonProxy");
        mTaker.take();
    }
}

测试代码

TakeLesson taker = new TakeLessonProxy(new Me());
taker.take();

打印出 This is TakeLessonProxy.I want someone to have Math class. I will give 50 yuan
第二个代理操作算是实现了
问题是以后如果还有别的代理操作呢?有没有方法把所有的都统一起来.
其实是有的,就是动态代理,它的核心类就是 InvocationHandler

public class ProxyHandler implements InvocationHandler {
    private Object object;
    public ProxyHandler(Object object) {
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //proxy其实就是ProxyHandler的实例
        //method就是接口方法
        //args就是接口的参数
        method.invoke(object, args);//调用真正的操作函数,其实还可以在之前或者之后添加别的操作
        return null;
    }
}

测试代码

Me me = new Me();
ProxyHandler handler = new ProxyHandler(me);
Buyer operator = (Buyer) Proxy.newProxyInstance(
        Buyer.class.getClassLoader(), // 传入ClassLoader
        new Class[] { Buyer.class }, // 传入要实现的接口
        handler); // 传入处理调用方法的InvocationHandler
operator.buy();
        
TakeLesson operator2 = (TakeLesson) Proxy.newProxyInstance(
        TakeLesson.class.getClassLoader(), // 传入ClassLoader
        new Class[] { TakeLesson.class }, // 传入要实现的接口
        handler); // 传入处理调用方法的InvocationHandler
operator2.take();

输出 I want to buy HUAWEI.I want someone to have Math class. I will give 50 yuan.
由此可见,动态代理可以代理多种行为(省掉了两个代理的实现类)具体的实现原理网上可以搜一下,不难找
那具体的动态代理操作又是如何实现的呢?
再以这段代码为例

Me me = new Me();
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); //设置系统属性
ProxyHandler handler = new ProxyHandler(me);
Buyer operator = (Buyer) Proxy.newProxyInstance(
        Buyer.class.getClassLoader(), // 传入ClassLoader
        new Class[] { Buyer.class }, // 传入要实现的接口
        handler); // 传入处理调用方法的InvocationHandler
operator.buy();

添加完System.getProperties(),就可以在项目名称\com\sun\proxy目录下找到对应的生成的代理类,然后用Luyten进行反编译得到

package com.sun.proxy;

import buy.*;
import java.lang.reflect.*;

public final class $Proxy0 extends Proxy implements Buyer
{
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;
    
    public $Proxy0(final InvocationHandler invocationHandler) {
        super(invocationHandler);
    }
    
    public final boolean equals(final Object o) {
        try {
            return (boolean)super.h.invoke(this, $Proxy0.m1, new Object[] { o });
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final String toString() {
        try {
            return (String)super.h.invoke(this, $Proxy0.m2, null);
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final void buy() {
        try {
            super.h.invoke(this, $Proxy0.m3, null);
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final int hashCode() {
        try {
            return (int)super.h.invoke(this, $Proxy0.m0, null);
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    static {
        try {
            $Proxy0.m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            $Proxy0.m2 = Class.forName("java.lang.Object").getMethod("toString", (Class<?>[])new Class[0]);
            $Proxy0.m3 = Class.forName("buy.Buyer").getMethod("buy", (Class<?>[])new Class[0]);
            $Proxy0.m0 = Class.forName("java.lang.Object").getMethod("hashCode", (Class<?>[])new Class[0]);
        }
        catch (NoSuchMethodException ex) {
            throw new NoSuchMethodError(ex.getMessage());
        }
        catch (ClassNotFoundException ex2) {
            throw new NoClassDefFoundError(ex2.getMessage());
        }
    }
}

我们就看buy函数,其实他就是调的InvocationHandler里面的invoke函数
于是,我们可以总结如下:

Proxy.newProxyInstance会生成一个代理类来继承接口,然后具体的实现还是由InvocationHandler的invoke函数决定的.如果没有method.invoke这一句,operator.buy()不会有任何输出

说白了,buy和takeLesson必须是相类似的操作(可以是不同接口).如果buy和takeLesson的操作差别很大,那么必须在invoke函数里面if else,那么这样的动态代理就没有意义
而网络请求的操作基本一样,都是构造url,顶多就是参数的区别.那么retrofit的动态代理基本也就明朗了

  • 1.new OkhttpClient(看代码就知道在build函数里面)
  • 2.继承InvocationHandler.当调用接口函数的时候就会走到invoke函数,接下来就很明显了,就是通过各种参数组成call,然后交给executor来执行(InvocationHandler的invoke函数肯定不会调用method.invoke,因为没有为接口实现具体的实现类)

3.retrofit

重点看一下create方法

  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);
          }
        });
  }

很明显出现了预料中的newProxyInstance动态代理。再仔细看看里面出现了啥
重点在 loadServiceMethod(method).invoke(args != null ? args : emptyArgs); 这一句
loadServiceMethod很明显就是加载了所有interface,然后是invoke方法
HttpServiceMethod的invoke

    @Override
    final @Nullable
    ReturnT invoke(Object[] args) {
        Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
        return adapt(call, args);
    }

看到了熟悉的OkHttpCall了吧。(Retrofit的build函数里面会new OkHttpClient的,其实build函数里面还生成了很多默认的一些配置,可以看看,比较简单)
由此可见,retrofit的动态代理代理的是OkHttpCall

相关文章

  • jdk动态代理和retrofit

    1.静态代理 比如说本人要买华为手机,可以自己买,也可以让别人帮着买 现在本人比较忙,所以决定让姐姐帮我代购(当然...

  • Spring的AOP原理分析

    一 动态代理 动态代理分为JDK动态代理和CGLIB动态代理 jdk动态代理 被代理类(目标类)和代理类必须实现同...

  • 面试系列~动态代理实现与原理

    动态代理有JDK动态代理, CGLIB动态代理, SpringAOP动态代理 一,JDK动态代理  jdk动态代理...

  • java面试宝典 五分钟了解spring代理 @Transact

    spring代理分为jdk动态代理和cglib代理 jdk动态代理 jdk动态代理是利用反射机制生成一个实现代理接...

  • 动态代理的两种方式

    静态代理就不说了,基本用到的都是动态代理。 Java中动态代理有JDK动态代理和CGLIB动态代理。 JDK代理的...

  • JDK和CGLIB动态代理区别

    JDK和CGLIB动态代理区别 一 JDK和CGLIB动态代理原理1、JDK动态代理利用拦截器(拦截器必须实现In...

  • spring aop

    JDK动态代理和CGLib代理 JDK的代理代理类 被代理接口 被代理实现类 启动类: jdk的动态代理是针对接口...

  • 动态代理

    Jdk 动态代理 Jdk动态代理,利用反射,实现 InvocationHandler 接口。Jdk 动态代理需要实...

  • 源码解析--JDK动态代理

    动态代理的两种方式JDK动态代理和cglib动态代理在上一篇中动态代理jdk和cglib的区别已经通过实例做了比较...

  • Java Spring中的动态代理cglib

    总结 JDK的动态代理和 Spring中的动态代理cglib区别 JDK 的动态代理 :针对实现了接口的类产生代理...

网友评论

      本文标题:jdk动态代理和retrofit

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