首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >jdk动态代理和retrofit

jdk动态代理和retrofit

作者头像
提莫队长
发布2020-06-02 15:30:50
2830
发布2020-06-02 15:30:50
举报
文章被收录于专栏:刘晓杰刘晓杰

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.静态代理
  • 2.动态代理
  • 3.retrofit
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档