美文网首页
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

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