jdk动态代理和retrofit

2019-09-28  本文已影响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的动态代理基本也就明朗了

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

上一篇下一篇

猜你喜欢

热点阅读