【微服务专题】——SpringCloud——Fegin——SpringCloud应用

Fegin使用——基本方式

@FeignClient(value = "XdocConsumer")
public interface XdocConsumer {
}
   /*
     传单个文件
    */
    @PostMapping(value = "/xdoc/upLoadFile/{employeeId}",produces = {MediaType.APPLICATION_JSON_UTF8_VALUE},
            consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    ResponseVO upLoadFile(@RequestPart(value = "file", required = false) MultipartFile file,@PathVariable("employeeId")String employeeId);
    /*
     传body参数
    */
    @PostMapping("/xdoc/backStageOper/")
    ResponseVO queryOnlySelfInvoice(@RequestBody XdocPo po)
}

   GitHub github = Feign.builder()
                         .decoder(new GsonDecoder())
                         .target(GitHub.class, "https://api.github.com");

Fegin使用——定义拦截器

@Configuration
@Slf4j
public class FeignInterceptor implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate template) {
        /*
          利用Tomcat全局工具类拿出请求参数
          并获取所有请求头
         */
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes == null) {
            return;
        }
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        Enumeration<String> headerNames = request.getHeaderNames();
        if (headerNames != null) {
            /*
              利用迭代器便利所有头,然后去request,getKey拿到value值
             */
            while (headerNames.hasMoreElements()) {
                String name = headerNames.nextElement();
                Enumeration<String> values = request.getHeaders(name);
                while (values.hasMoreElements()) {
                    String value = values.nextElement();.
                    /*
                      对于multipart的特殊处理
                     */
                    if(name.toLowerCase().equals("content-type") && value.contains("multipart/form-data")){
                        value= "application/json";
                    }
                    /*
                      在模板中一个个value复制过来,复制请求头
                     */
                    template.header(name, value);
                }
            }
        }
    }
}

Fegin使用——自定义异常处理器

异常解析器

@Configuration
public class FeginExcpetionDecoder {
    /**
     * @HttpStatus状态码200-300的时候进入这个处理器进行全局fegin异常处理 通过ErrorDecoder对异常封装成可以识别的异常丢给全局处理器
     */
    @Bean
    public ErrorDecoder errorDecoder() {
        return new ErrorDecoder() {
            public Exception decode(String methodKey, Response response) {
                if (response.status() == 404) {
                    return new ApiRemoteNotFoundException("远程调用404,方法名为:" + methodKey);
                }
                String feginDataJson = null;
                Exception exception = null;
                try {
                    feginDataJson = Util.toString(response.body().asReader(Charset.defaultCharset()));
                    ResponseVO errorResponseVO = JSON.parseObject(feginDataJson, ResponseVO.class);
                    exception= discernRemoteException(errorResponseVO);
                } catch (JSONException e) {
                    /**
                     * 如果JSON格式不一致则会抛出这个异常
                     * 比如:404错误类型由tomcat特殊封装一个VO返回,这个VO的结构如下
                     *    status:……
                     *    error:……
                     */
                    exception = new ApiRemoteParseException(
                            e.getMessage()+JSON.parseObject(feginDataJson).get("error").toString()
                    );
                } catch (Exception e) {
                    /**
                     * 未知异常打印日志信息
                     */
                    exception = new ApiNativeNoneException(e.getMessage());
                }
                return exception;
            }
        };
    }
    public static ApiRemoteBaseException discernRemoteException(ResponseVO responseVO){
        if(responseVO.getCode()==404){
            return new ApiRemoteNotFoundException(responseVO.getErrorTip());
        }else if(responseVO.getCode()>=500&&responseVO.getCode()<10000){
            return new ApiRemoteServiceException(responseVO);
        }
        return new ApiRemoteNoneException(responseVO);
    }
}

全局异常处理

@RestControllerAdvice
public class WebGlobalExceptionHandler   {
    @ResponseBody
    @ExceptionHandler(ApiRemoteBaseException.class)
    public ResponseVO apiRemoteException(ApiRemoteBaseException ex, HttpServletResponse response) {
        response.setStatus(ex.getCode());
        ExceptionUtils.errorLogOutput("Api远程调用异常————日志提示信息:"+ex.getMsg());
        ExceptionUtils.errorLogOutput("Api远程调用异常————日志提示信息:"+ex.getErrorTip());
        return  ExceptionUtils.errorApiRmoteExceptionView(ex);
    }
    @ResponseBody
    @ExceptionHandler(ApiNativeNoneException.class)
    public ResponseVO apiNoneException(ApiNativeNoneException ex, HttpServletResponse response) {
        response.setStatus(ex.getCode());
        ExceptionUtils.errorLogOutput("Api未知异常————日志提示信息:"+ex.getMsg());
        ExceptionUtils.errorLogOutput("Api未知异常————日志提示信息:"+ex.getErrorTip());
        return ExceptionUtils.errorNativeUnknownExcpetionView(ex);
    }
    @ResponseBody
    @ExceptionHandler(Exception.class)
    public ResponseVO exception(Exception ex, HttpServletResponse response) {
        response.setStatus(500);
        ExceptionUtils.errorLogOutput("全局未知异常————日志提示信息:"+ex.getMessage());
        return ExceptionUtils.errorNativeUnknownExcpetionView(ex);
    }
}

Fegin源码——创建机制

由于fegin是由hytyric创建的,所以我们学完hytric再来讨论这个问题

Fegin源码——调用机制

在这里插入图片描述

SynchronousMethodHandler——请求与响应衔接调用层

这一层主要是根据http的状态去决定调用不同的编解码实现类

final class SynchronousMethodHandler implements MethodHandler {
  /*
    Fegin完成api发送的组件存储
   */
  private static final long MAX_RESPONSE_BUFFER_SIZE = 8192L;
  private final MethodMetadata metadata;//封装了fegin接口的解析到的方法的核心数据,比如,返回值类型
  private final Target<?> target;//目标代理类
  private final Client client;//创建网络请求的类
  private final Retryer retryer;
  private final List<RequestInterceptor> requestInterceptors;
  private final RequestTemplate.Factory buildTemplateFromArgs;//请求模板工厂
  private final Options options;//一些超时时间配置,各个粒度
  private final ExceptionPropagationPolicy propagationPolicy;

  private final Decoder decoder;//解码器,一般不用这个,有下面的处理器
  private final AsyncResponseHandler asyncResponseHandler;//处理器

  /*
    Fegin完成api发送的组件的具体实现类全部由外部定制
   */
  private SynchronousMethodHandler(Target<?> target, Client client, Retryer retryer,
      List<RequestInterceptor> requestInterceptors, Logger logger,
      Logger.Level logLevel, MethodMetadata metadata,
      RequestTemplate.Factory buildTemplateFromArgs, Options options,
      Decoder decoder, ErrorDecoder errorDecoder, boolean decode404,
      boolean closeAfterDecode, ExceptionPropagationPolicy propagationPolicy,
      boolean forceDecoding) {

    this.target = checkNotNull(target, "target");
    this.client = checkNotNull(client, "client for %s", target);
    this.retryer = checkNotNull(retryer, "retryer for %s", target);
    this.requestInterceptors =
        checkNotNull(requestInterceptors, "requestInterceptors for %s", target);
    this.logger = checkNotNull(logger, "logger for %s", target);
    this.logLevel = checkNotNull(logLevel, "logLevel for %s", target);
    this.metadata = checkNotNull(metadata, "metadata for %s", target);
    this.buildTemplateFromArgs = checkNotNull(buildTemplateFromArgs, "metadata for %s", target);
    this.options = checkNotNull(options, "options for %s", target);
    this.propagationPolicy = propagationPolicy;

    if (forceDecoding) {//默认不开启这个
      this.decoder = decoder;
      this.asyncResponseHandler = null;
    } else {//使用响应处理器进行编解码
      this.decoder = null;
      this.asyncResponseHandler = new AsyncResponseHandler(logLevel, logger, decoder, errorDecoder,
          decode404, closeAfterDecode);
    }
  }
  /*
    执行请求,argv请求参数
   */
  @Override
  public Object invoke(Object[] argv) throws Throwable {
    RequestTemplate template = buildTemplateFromArgs.create(argv);
    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 {
    /*
      利用template执行请求拦截连,然后返回最终的request实体
     */
    Request request = targetRequest(template);
    Response response;
    long start = System.nanoTime();//计算时间
    try {
      /*
       利用网络请求类发起请求
       然后将请求和响应组成在一起返回response 
       */
      response = client.execute(request, options);
      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;
    }
  }
  Request targetRequest(RequestTemplate template) {
    for (RequestInterceptor interceptor : requestInterceptors) {
      interceptor.apply(template);
    }
    return target.apply(template);
  }

 }

AsyncResponseHandler ——响应结果处理层

class AsyncResponseHandler {

  private static final long MAX_RESPONSE_BUFFER_SIZE = 8192L;
  /*
    处理的组件主要是就是编辑码组件
   */
  private final Level logLevel;
  private final Logger logger;

  private final Decoder decoder;
  private final ErrorDecoder errorDecoder;
  private final boolean decode404;
  private final boolean closeAfterDecode;

  AsyncResponseHandler(Level logLevel, Logger logger, Decoder decoder, ErrorDecoder errorDecoder,
      boolean decode404, boolean closeAfterDecode) {
    super();
    this.logLevel = logLevel;
    this.logger = logger;
    this.decoder = decoder;
    this.errorDecoder = errorDecoder;
    this.decode404 = decode404;
    this.closeAfterDecode = closeAfterDecode;
  } 
  /*
    判断是否没返回值
   */
  boolean isVoidType(Type returnType) {
    return Void.class == returnType || void.class == returnType;
  }

  void handleResponse(CompletableFuture<Object> resultFuture,
                      String configKey,
                      Response response,
                      Type returnType,
                      long elapsedTime) {
    boolean shouldClose = true;
    try {
      if (Response.class == returnType) {
       /*
         对于一些空情况的优先处理
        */
        if (response.body() == null) {
          resultFuture.complete(response);
        } else if (response.body().length() == null
            || response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
          shouldClose = false;
          resultFuture.complete(response);
        } else {
          final byte[] bodyData = Util.toByteArray(response.body().asInputStream());
          resultFuture.complete(response.toBuilder().body(bodyData).build());
        }
      } 
     /*
        http状态码200-300则调用正常的解析器
      */
     else if (response.status() >= 200 && response.status() < 300) {
        /*
         无返回值处理
         */
        if (isVoidType(returnType)) {
          resultFuture.complete(null);
        } 
        /*
         有返回值处理
         */
       else {
          final Object result = decode(response, returnType);
          shouldClose = closeAfterDecode;
          resultFuture.complete(result);
        }
      } 
      /*
        404
      */
      else if (decode404 && response.status() == 404 && !isVoidType(returnType)) {
        final Object result = decode(response, returnType);
        shouldClose = closeAfterDecode;
        resultFuture.complete(result);
      } 
      /*
        异常解析器
      */
    else {
        resultFuture.completeExceptionally(errorDecoder.decode(configKey, response));
      }
    } catch (final IOException e) {
      if (logLevel != Level.NONE) {
        logger.logIOException(configKey, logLevel, e, elapsedTime);
      }
      resultFuture.completeExceptionally(errorReading(response.request(), response, e));
    } catch (final Exception e) {
      resultFuture.completeExceptionally(e);
    } finally {
      if (shouldClose) {
        ensureClosed(response.body());
      }
    }

  Object decode(Response response, Type type) throws IOException {
    /*
      调用解析器返回Object给到用到的地方
     */
    try {
      return decoder.decode(response, type);
    } catch (final FeignException e) {
      throw e;
    } catch (final RuntimeException e) {
      throw new DecodeException(response.status(), e.getMessage(), response.request(), e);
    }
  }
}

默认的解码器
在这里插入图片描述

RequestTemplate ——请求目标组件

框架一般都喜欢将单值装饰城对象,以方便面向对象的扩展

public final class RequestTemplate implements Serializable {

  private static final Pattern QUERY_STRING_PATTERN = Pattern.compile("(?<!\\{)\\?");
  private final Map<String, QueryTemplate> queries = new LinkedHashMap<>();//查询参数封装
  private final Map<String, HeaderTemplate> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);//请求头封装
  private boolean resolved = false;
  private UriTemplate uriTemplate;//请求地址封装//
  private BodyTemplate bodyTemplate;//请求body封装//
  private HttpMethod method;//请求方式封装
  private transient Charset charset = Util.UTF_8;//字符集
  private Request.Body body = Request.Body.empty();
  private boolean decodeSlash = true;
  private CollectionFormat collectionFormat = CollectionFormat.EXPLODED;
  private MethodMetadata methodMetadata;//接口方法的核心数据
  private Target<?> feignTarget;//代理对象的保存
 }

Fegin源码——解析机制(待完善)

Fegin源码——HystrixCommand(待完善)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值