天天看点

feign基础源码解析(初始化,调用过程)

实例调用过程

feign的核心主要分两块:

1,初始化

feign通过Feign.builder() 构造器构建传递初始化参数,如:发起http的工具,序列化工具,目标类,生产者地址等参数

然后解析目标类注解为每个方法生成对应的MethodHandler ,

然后使用jdk动态代理为目标类生成代理实例ReflectiveFeign.FeignInvocationHandler

2,调用过程

调用目标类实例方法实际调用的是代理对象 ReflectiveFeign.FeignInvocationHandler.invoke–>

同步调用方法处理器 SynchronousMethodHandler.invoke–> ApacheHttp装饰者 ApacheHttpClient.execute

测试接口
public interface TestFeignClient {
    @GET
    @Path("test")
    String test(String str);

}
           
1,初始化过程,脱离spring自动装配的情况下,使用TestFeignClient,创建目标类接口的代理类实例
TestFeignClient target = Feign.builder()
            .client(new ApacheHttpClient())
            .contract(new JAXRS2Contract())
            .decoder(new JacksonDecoder())
            .encoder(new JacksonEncoder())
            .target(TestFeignClient.class, "http://" + testClient);
            
    Feign.builder() 基础构建器
    
    .client(new ApacheHttpClient()) 选择具体发起http请求的工具
        由ApacheHttpClient 类实现 实现feign.Client 接口,
        核心实现方法execute(),通过解析转换feign.Request 为 org.apache.http.HttpResponse
        然后通过apache.HttpClient 发起请求
        
    .contract(new JAXRS2Contract()) 使用 JAX-RS 2 注解标识请求
    
    .decoder(new JacksonDecoder())  解码器
    .encoder(new JacksonEncoder())  编码器
    
    .target(TestFeignClient.class, "http://" + testClient); 使用jdk动态代理生成代理对象
        基础构建之后创建默认对象 ReflectiveFeign
        1,new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
        2,调用 ReflectiveFeign.newInstance(target); 创建实例
        
          @Override
          public <T> T newInstance(Target<T> target) {
            //解析接口中方法请求注解 和参数相关元数据
            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()) {
              if (method.getDeclaringClass() == Object.class) {
                continue;
              } else if (Util.isDefault(method)) {
                DefaultMethodHandler handler = new DefaultMethodHandler(method);
                defaultMethodHandlers.add(handler);
                methodToHandler.put(method, handler);
              } else {
                methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
              }
            }
            //生成代理处理器,调用的还是ReflectiveFeign 由他来的内部类FeignInvocationHandler实现jdk 
            // 动态代理类 InvocationHandler接口
            //      @Override
            //      public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
            //        return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
            //      }
            //
            InvocationHandler handler = factory.create(target, methodToHandler);
            T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
                new Class<?>[] {target.type()}, handler);
        
            for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
              defaultMethodHandler.bindTo(proxy);
            }
            return proxy;
          }
           
2,接口调用过程
我们使用上一步获取到的TestFeignClient实例直接调用 接口的方法TestFeignClient.test("aaa")
   当我们调用此实例的方法实际调用的是代理 ReflectiveFeign.FeignInvocationHandler.invoke 方法
           

ReflectiveFeign.FeignInvocationHandler.invoke

//目标类
        private final Target target;
        //解析目标类缓存方法对应请求
        private final Map<Method, MethodHandler> dispatch;
       @Override
       public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
         //equals/hashCode/toString不发起请求
         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();
         }
   
         //实际调用
         return dispatch.get(method).invoke(args);
       }
           

SynchronousMethodHandler 继承 MethodHandler 实现同步调用请求

@Override
         public Object invoke(Object[] argv) throws Throwable {
            //通过请求参数生成请求模板
           RequestTemplate template = buildTemplateFromArgs.create(argv);
           //请求相关参数,timeout等
           Options options = findOptions(argv);
           //重试机制
           Retryer retryer = this.retryer.clone();
           while (true) {
             try {
                //发起请求
               return executeAndDecode(template, options);
             } catch (RetryableException e) {
               try {
                 retryer.continueOrPropagate(e);
               } catch (RetryableException th) {
                 Throwable cause = th.getCause();
                 if (propagationPolicy == UNWRAP && cause != null) {
                   throw cause;
                 } else {
                   throw th;
                 }
               }
               if (logLevel != Logger.Level.NONE) {
                 logger.logRetry(metadata.configKey(), logLevel);
               }
               continue;
             }
           }
         }
      
      Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
        //生成feign 请求对象
        Request request = targetRequest(template);
    
        if (logLevel != Logger.Level.NONE) {
          logger.logRequest(metadata.configKey(), logLevel, request);
        }
    
        Response response;
        long start = System.nanoTime();
        try {
          //调用 ApacheHttpClient feign 的装饰者请求类
          response = client.execute(request, options);
          // ensure the request is set. TODO: remove in Feign 12
          response = response.toBuilder()
              .request(request)
              .requestTemplate(template)
              .build();
        } catch (IOException e) {
          if (logLevel != Logger.Level.NONE) {
            logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));
          }
          throw errorExecuting(request, e);
        }
        long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
    
    
        if (decoder != null)
          return decoder.decode(response, metadata.returnType());
    
        CompletableFuture<Object> resultFuture = new CompletableFuture<>();
        asyncResponseHandler.handleResponse(resultFuture, metadata.configKey(), response,
            metadata.returnType(),
            elapsedTime);
    
        try {
          if (!resultFuture.isDone())
            throw new IllegalStateException("Response handling not done");
    
          return resultFuture.join();
        } catch (CompletionException e) {
          Throwable cause = e.getCause();
          if (cause != null)
            throw cause;
          throw e;
        }
      }
           

ApacheHttpClient.execute 最终调用

private final HttpClient client;
      @Override
      public Response execute(Request request, Request.Options options) throws IOException {
        HttpUriRequest httpUriRequest;
        try {
          //feign request 转换为ApacheHttpClient httpUriRequest
          httpUriRequest = toHttpUriRequest(request, options);
        } catch (URISyntaxException e) {
          throw new IOException("URL '" + request.url() + "' couldn't be parsed into a URI", e);
        }
        //由 ApacheHttpClient 发起最终请求
        HttpResponse httpResponse = client.execute(httpUriRequest);
        return toFeignResponse(httpResponse, request);
      }