美文网首页
Feign源码学习(2)

Feign源码学习(2)

作者: 無式 | 来源:发表于2017-09-02 10:17 被阅读0次

    ReflectiveFeign

    • Feign的使用方法我们可以推测,它的内部实现是利用了Java反射解析Api方法上的参数与注解,生成代理实现类。所以Feign的实现类名称就叫作ReflectiveFeign
     /**
      * ReflectiveFeign.newInstance 生成proxy代理实现的主逻辑
      * @param Target<T> 在Feign.target中传入的代理目标Class与host url参数
      */
      public <T> T newInstance(Target<T> target) {
        //核心逻辑入口,反射解析目标Class,得到MethodHandler集合
        Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
        Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
        List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
    
        for (Method method : target.type().getMethods()) {
          //Object的方法(如toString之类的)就无视
          if (method.getDeclaringClass() == Object.class) {
            continue;
          } 
          //Default方法处理
          else if(Util.isDefault(method)) {
            DefaultMethodHandler handler = new DefaultMethodHandler(method);
            defaultMethodHandlers.add(handler);
            methodToHandler.put(method, handler);
          } 
          //Http请求代理方法
          else {
            methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
          }
        }
    
        //主要逻辑,生成proxy,实现其中的Rest请求方法。
        //InvocationHandler实现类为FeignInvocationHandler
        InvocationHandler handler = factory.create(target, methodToHandler);
        T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[]{target.type()}, handler);
    
        //处理其他默认方法,绑定到Proxy上
        for(DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
          defaultMethodHandler.bindTo(proxy);
        }
        return proxy;
      }
    
    • ReflectiveFeign.newInstance主要分为两块逻辑:
      1.反射解析代理目标ClassMethod与注解,得到MethodHandler
      2.生成Proxy对象,绑定Proxy的方法实现。
    • 如何从代理目标Class中解析出要实现的HTTP调用方法,则是整个Feign框架的核心业务。完成这个工作的是ParseHandlersByName.apply方法 。
    • 将解析的结果绑定到Proxy对象,基本上按照Java代理的标准模式处理。主要实现逻辑在FeignInvocationHandler中。

    FeignInvocationHandler

    • 先从结果开始分析,ParseHandlersByName.apply解析出来的结果MethodHandler是一个抽象接口:
      interface MethodHandler {
        Object invoke(Object[] argv) throws Throwable;
      }
    
    • 因为这个结果最后使用在代理绑定中,所以对外暴露方法只需要一个invoke就足够了。
    • FeignInvocationHandlerJava代理中java.lang.reflect.InvocationHandler的实现类,实现了代理对象中方法需要完成的逻辑:
      //FeignInvocationHandler部分代码
      static class FeignInvocationHandler implements InvocationHandler {
        //代理目标Class
        private final Target target;
        //持有前面解析出来的MethodHandler集合
        private final Map<Method, MethodHandler> dispatch;
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          //一些特殊方法的处理
          if ("equals".equals(method.getName())) {
            try {
              Object otherHandler =
                  args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
              return equals(otherHandler);
            } catch (IllegalArgumentException e) {
              return false;
            }
          } else if ("hashCode".equals(method.getName())) {
            return hashCode();
          } else if ("toString".equals(method.getName())) {
            return toString();
          }
          //Rest请求方法调用,并返回结果
          return dispatch.get(method).invoke(args);
        }
      }
    
    • InvocationHandler中只有一个invoke方法需要实现,入参是调用的方法标识与调用参数,返回结果。
    • FeignInvocationHandler的工作就是找到要执行方法的代理MethodHandler,调用并return
    • 这样FeignInvocationHandler就可以参与到生成Proxy的实现中去。
    • 看到这里我们就可以发现,真正发生Rest请求调用的是在MethodHandler的实现类SynchronousMethodHandler中。

    相关文章

      网友评论

          本文标题:Feign源码学习(2)

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