feign构建与调用全流程分析

源码分析 专栏收录该内容
5 篇文章 0 订阅

基于springcloud的灰度实现方案(一)

基于springcloud的灰度实现方案(二)

@Configuration配置加载分析

之前介绍了灰度方案以及实现,分析feign调用的时候,有点不太尽兴,这次再丰富一下。

首先,我们在feign调用时,使用了FeignClient注解。

#接口调用
@FeignClient("demo-service")
public interface DemoServiceFeginClient {
}
# 开启feign
@EnableFeignClients(basePackages = {"com.yxkong.api"})
public class ApiStarter {
}

定位下发现注解位于

FeignClient和EnableFeignClients  位于
Maven: 
    org.springframework.cloud
    spring-cloud-openfeign-core
    2.2.8.RELEASE

我们看下EnableFeignClients的源码

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
//关键点,利用spring的动态注册bean的机制,在 Configuration配置加载分析 中已经详细解说
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware 
  @Override  
  public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry)
     //如果有配置defaultConfiguration 则注册到ioc
    registerDefaultConfiguration(metadata, registry);
    //根据配置扫描的feignClient,生成bean并注册到registry    
    registerFeignClients(metadata, registry);
  }    
  public void registerFeignClients(AnnotationMetadata metadata,BeanDefinitionRegistry registry) {

    LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();
    Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
    //从EnableFeignClients查找配置的clients
    final Class<?>[] clients = attrs == null ? null: (Class<?>[]) attrs.get("clients");
    if (clients == null || clients.length == 0) {
      ClassPathScanningCandidateComponentProvider scanner = getScanner();
      scanner.setResourceLoader(this.resourceLoader);
      //设置过滤条件FeignClient
      scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class));
      //在getBasePackages将所有的路径聚合
      Set<String> basePackages = getBasePackages(metadata);
      for (String basePackage : basePackages) {
        //将扫描到的所有FeignClient放入candidateComponents
        candidateComponents.addAll(scanner.findCandidateComponents(basePackage));
      }
    }
    for (BeanDefinition candidateComponent : candidateComponents) {
      if (candidateComponent instanceof AnnotatedBeanDefinition) {    
      //构建FeignClientFactoryBean注入ioc中
        registerFeignClient(registry, annotationMetadata, attributes);
      }
    }
  }
    private void registerFeignClient(BeanDefinitionRegistry registry,
      AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
    String className = annotationMetadata.getClassName();
    Class clazz = ClassUtils.resolveClassName(className, null);
    ConfigurableBeanFactory beanFactory = registry instanceof ConfigurableBeanFactory
        ? (ConfigurableBeanFactory) registry : null;
    String contextId = getContextId(beanFactory, attributes);
    String name = getName(attributes);
    //真正的是这块,构建一个FeignClientFactoryBean并注入到ioc中
    FeignClientFactoryBean factoryBean = new FeignClientFactoryBean();
    factoryBean.setBeanFactory(beanFactory);
    // 注入对象的名称是配置的或者spring自动生成
    factoryBean.setName(name);
    factoryBean.setContextId(contextId);
    //对象类型就是FeignClient标注的对象本身(如此通过@Autowird能快速获取到对应的对象)
    factoryBean.setType(clazz);
    BeanDefinitionBuilder definition = BeanDefinitionBuilder
        .genericBeanDefinition(clazz, () -> {
          factoryBean.setUrl(getUrl(beanFactory, attributes));
          factoryBean.setPath(getPath(beanFactory, attributes));
          factoryBean.setDecode404(Boolean
              .parseBoolean(String.valueOf(attributes.get("decode404"))));
          Object fallback = attributes.get("fallback");
          if (fallback != null) {
            factoryBean.setFallback(fallback instanceof Class
                ? (Class<?>) fallback
                : ClassUtils.resolveClassName(fallback.toString(), null));
          }
          Object fallbackFactory = attributes.get("fallbackFactory");
          if (fallbackFactory != null) {
            factoryBean.setFallbackFactory(fallbackFactory instanceof Class
                ? (Class<?>) fallbackFactory
                : ClassUtils.resolveClassName(fallbackFactory.toString(),
                    null));
          }
          //从FeignClientFactoryBean中获取构建的Feign对象
          return factoryBean.getObject();
        });

    BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
        qualifiers);
    //最终将Feign对象注入到IOC中
    BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
  }
}

我们看到FeignClientFactoryBean.getObject()中调用了getTarget()方法

public class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean,
    ApplicationContextAware, BeanFactoryAware {
  @Override
  public Object getObject() {
    return getTarget();
  }
  <T> T getTarget() {
    FeignContext context = beanFactory != null? beanFactory.getBean(FeignContext.class): applicationContext.getBean(FeignContext.class);
    // 这块是关键,构建了一个Feign对象,在这里设置feign具备哪些功能
    Feign.Builder builder = feign(context);
    //没有配置url的时候走下面的流程
    if (!StringUtils.hasText(url)) {
      if (!name.startsWith("http")) {
        url = "http://" + name;
      }
      else {
        url = name;
      }
      url += cleanPath();            
      return (T) loadBalance(builder, context,new HardCodedTarget<>(type, name, url));
    }
    if (StringUtils.hasText(url) && !url.startsWith("http")) {
      url = "http://" + url;
    }
    String url = this.url + cleanPath();
    Client client = getOptional(context, Client.class);
    if (client != null) {
      if (client instanceof LoadBalancerFeignClient) {
        // not load balancing because we have a url,
        // but ribbon is on the classpath, so unwrap
        client = ((LoadBalancerFeignClient) client).getDelegate();
      }
      if (client instanceof FeignBlockingLoadBalancerClient) {
        // not load balancing because we have a url,
        // but Spring Cloud LoadBalancer is on the classpath, so unwrap
        client = ((FeignBlockingLoadBalancerClient) client).getDelegate();
      }
      if (client instanceof RetryableFeignBlockingLoadBalancerClient) {
        // not load balancing because we have a url,
        // but Spring Cloud LoadBalancer is on the classpath, so unwrap
        client = ((RetryableFeignBlockingLoadBalancerClient) client)
            .getDelegate();
      }
      builder.client(client);
    }
    Targeter targeter = get(context, Targeter.class);
    return (T) targeter.target(this, builder, context,
        new HardCodedTarget<>(type, name, url));
  }
  protected Feign.Builder feign(FeignContext context) {
    FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
    Logger logger = loggerFactory.create(type);

    // @formatter:off
    Feign.Builder builder = get(context, Feign.Builder.class)
        // required values
        .logger(logger)
        .encoder(get(context, Encoder.class))
        .decoder(get(context, Decoder.class))
        .contract(get(context, Contract.class));
    // @formatter:on
    // 关键点  
    configureFeign(context, builder);
    applyBuildCustomizers(context, builder);

    return builder;
  }
  protected void configureFeign(FeignContext context, Feign.Builder builder) {
      //配置Feign
      configureUsingConfiguration(context, builder);
      //从属性中获取配feign的属性
      configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()),builder);
      configureUsingProperties(properties.getConfig().get(contextId), builder);
  }
  protected void configureUsingConfiguration(FeignContext context,
      Feign.Builder builder) {
      主要包含:
      1,日志级别
      2,Retryer
      3,ErrorDecoder
      4,Request.Options
      5,RequestInterceptor
      6,QueryMapEncoder
      7,ExceptionPropagationPolicy 异常策略
  }
  protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
      HardCodedTarget<T> target) {
    Client client = getOptional(context, Client.class);
    if (client != null) {
      builder.client(client);
      //Targeter是HystrixTargeter
      Targeter targeter = get(context, Targeter.class);
      //具体看HystrixTargeter.target 方法
      return targeter.target(this, builder, context, target);
    }
    //看这个自定义异常就能发现Client是spring-cloud-starter-netflix-ribbon or spring-cloud-starter-loadbalancer这两个里面的
    throw new IllegalStateException(
        "No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon or spring-cloud-starter-loadbalancer?");
  }
  
}
class HystrixTargeter implements Targeter {
  public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
      FeignContext context, Target.HardCodedTarget<T> target) {
        return feign.target(target);
      }
}
public abstract class Feign {
  //构建了Feign的默认参数
  public static class Builder {
      private InvocationHandlerFactory invocationHandlerFactory =
        new InvocationHandlerFactory.Default();
  }
  public <T> T target(Target<T> target) {
     return build().newInstance(target);
  }
  public Feign build() {
     SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
          new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
              logLevel, decode404, closeAfterDecode, propagationPolicy, forceDecoding);
      ParseHandlersByName handlersByName =
          new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
              errorDecoder, synchronousMethodHandlerFactory);
     //invocationHandlerFactory 在Builder中构建了默认InvocationHandlerFactory.Default()
     return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
  }
}
public class ReflectiveFeign extends Feign {
  public <T> T newInstance(Target<T> target) {
     // targetToHandlersByName内构建了SynchronousMethodHandler和BuildTemplateByResolvingArgs
     Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
     // factory 就是在Feign.build传入的,是Feign.Builder初始化的
     //在此create的时候ReflectiveFeign.FeignInvocationHandler(target, dispatch);
     InvocationHandler handler = factory.create(target, methodToHandler);
     //最后代理的handler是FeignInvocationHandler
     T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
        new Class<?>[] {target.type()}, handler);
     return proxy;
  }
  static class FeignInvocationHandler implements InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    }
  }
}
//FeignClient 没有配置url,只有一个服务名
@FeignClient("demo-service")
public interface DemoServiceFeignClient {
    @RequestMapping(value = "/demo/hello",method = {RequestMethod.GET})
    ResultBean hello();

}

综上所述,在从FeignClientFactoryBean.getObject的时候,根据配置参数构建了一个Feign。

整个feign对象的生成流程如下:

图片

这里又有两个点:

1,Client 用哪个?怎么注入的?

2,Targeter用哪个?

回过头来,继续看

  protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
      HardCodedTarget<T> target) {
    //从spring的context中获取指定类型Client的实例
    Client client = getOptional(context, Client.class);
    if (client != null) {
      builder.client(client);
      //从spring的context中获取指定类型Targeter的实例
      //Targeter是HystrixTargeter
      Targeter targeter = get(context, Targeter.class);
      return targeter.target(this, builder, context, target);
    }
    //看这个自定义异常就能发现Client是spring-cloud-starter-netflix-ribbon or spring-cloud-starter-loadbalancer这两个里面的
    throw new IllegalStateException(
        "No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon or spring-cloud-starter-loadbalancer?");
  }

图片

其中

Defult是feign的默认实现,内部使用HttpURLConnection 执行调用;

LoadBalancerFeignClient是在org.springframework.cloud.openfeign.ribbon包下;

剩下的两个在org.springframework.cloud.openfeign.loadbalancer 包下。

这种注入性的配置在springboot里一般都在configuration中。

看下spring.factorieswe文件

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.openfeign.ribbon.FeignRibbonClientAutoConfiguration,\
org.springframework.cloud.openfeign.hateoas.FeignHalAutoConfiguration,\
org.springframework.cloud.openfeign.FeignAutoConfiguration,\
org.springframework.cloud.openfeign.encoding.FeignAcceptGzipEncodingAutoConfiguration,\
org.springframework.cloud.openfeign.encoding.FeignContentGzipEncodingAutoConfiguration,\
org.springframework.cloud.openfeign.loadbalancer.FeignLoadBalancerAutoConfiguration

AutoConfiguration 是有顺序的。

在FeignRibbonClientAutoConfiguration中,

//第一个就是HttpClientFeignLoadBalancedConfiguration
@Import({ HttpClientFeignLoadBalancedConfiguration.class,
    OkHttpFeignLoadBalancedConfiguration.class,
    HttpClient5FeignLoadBalancedConfiguration.class,
    DefaultFeignLoadBalancedConfiguration.class })
public class FeignRibbonClientAutoConfiguration {
}
@Configuration(proxyBeanMethods = false)
//没引入这个类,不执行
@ConditionalOnClass(ApacheHttpClient.class)
@ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)
@Conditional(HttpClient5DisabledConditions.class)
//这里又导入了HttpClient
@Import(HttpClientFeignConfiguration.class)
class HttpClientFeignLoadBalancedConfiguration {
}
@Configuration(proxyBeanMethods = false)
//这个也没引入,不执行
@ConditionalOnClass(OkHttpClient.class)
@ConditionalOnProperty("feign.okhttp.enabled")
@Import(OkHttpFeignConfiguration.class)
class OkHttpFeignLoadBalancedConfiguration {
}
@Configuration(proxyBeanMethods = false)
//这个没引入,不执行
@ConditionalOnClass(ApacheHttp5Client.class)
@ConditionalOnProperty(value = "feign.httpclient.hc5.enabled", havingValue = "true")
@Import(HttpClient5FeignConfiguration.class)
class HttpClient5FeignLoadBalancedConfiguration {
}

再看最后一个

@Configuration(proxyBeanMethods = false)
class DefaultFeignLoadBalancedConfiguration {

  @Bean
  @ConditionalOnMissingBean
  public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
      SpringClientFactory clientFactory) {
    return new LoadBalancerFeignClient(new Client.Default(null, null), cachingFactory,
        clientFactory);
  }
}

到这,默认的Client 的注入有了是LoadBalancerFeignClient。

我们再看

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Feign.class)
@EnableConfigurationProperties({ FeignClientProperties.class,
    FeignHttpClientProperties.class, FeignEncoderProperties.class })
@Import(DefaultGzipDecoderConfiguration.class)
public class FeignAutoConfiguration {
  @Configuration(proxyBeanMethods = false)
  @Conditional(DefaultFeignTargeterConditions.class)
  protected static class DefaultFeignTargeterConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public Targeter feignTargeter() {
      return new DefaultTargeter();
    }

  }

  @Configuration(proxyBeanMethods = false)
  @Conditional(FeignCircuitBreakerDisabledConditions.class)
  @ConditionalOnClass(name = "feign.hystrix.HystrixFeign")
  //优先使用这个
  @ConditionalOnProperty(value = "feign.hystrix.enabled", havingValue = "true",
      matchIfMissing = true)
  protected static class HystrixFeignTargeterConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public Targeter feignTargeter() {
      return new HystrixTargeter();
    }

  }

  @Configuration(proxyBeanMethods = false)
  @ConditionalOnClass(CircuitBreaker.class)
  @ConditionalOnProperty(value = "feign.circuitbreaker.enabled", havingValue = "true")
  protected static class CircuitBreakerPresentFeignTargeterConfiguration {

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnBean(CircuitBreakerFactory.class)
    public Targeter circuitBreakerFeignTargeter(
        CircuitBreakerFactory circuitBreakerFactory) {
      return new FeignCircuitBreakerTargeter(circuitBreakerFactory);
    }

  }
}

到这,默认的Targeter 是 HystrixTargeter。

我们再看

 protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
      HardCodedTarget<T> target) {
    Client client = getOptional(context, Client.class);
    if (client != null) {
      builder.client(client);
      Targeter targeter = get(context, Targeter.class);
      //最后返回的是targeter.target
      return targeter.target(this, builder, context, target);
    }
    //看这个自定义异常就能发现Client是spring-cloud-starter-netflix-ribbon or spring-cloud-starter-loadbalancer这两个里面的
    throw new IllegalStateException(
        "No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon or spring-cloud-starter-loadbalancer?");
  }
  //具体实现
class HystrixTargeter implements Targeter {

  @Override
  public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
      FeignContext context, Target.HardCodedTarget<T> target) {
   
    //最终走的是feign.target()
    return feign.target(target);
  }
}
public abstract class Feign {
    public <T> T target(Target<T> target) {
      //build()构建了一个ReflectiveFeign,然后执行newInstance
      return build().newInstance(target);
    }
    public Feign build() {
      return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
    }
}
public class ReflectiveFeign extends Feign {
    public <T> T newInstance(Target<T> target) {
      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;
    }
}

到此feign初始化的流程分析完了。

然后我们断点验证下:

图片

确实如分析所说。

Feign生成流程分析完毕。

接下来我们分析下Feign使用流程

    @Autowired
    private DemoServiceFeignClient demoServiceFeginClient;
    @GetMapping("hello")
    public ResultBean hello(){
        String msg = "api进入的版本号是:"+version;
        log.info(msg);
        return demoServiceFeginClient.hello();
    }

我们知道Autowired是通过类型查找的,所以这块一定会找到一个DemoServiceFeignClient的Proxy对象,Proxy的handler是FeignInvocationHandler

我们梳理下我们从上面得到的信息:

Feign使用的是: ReflectiveFeign
Proxy的源也是: ReflectiveFeign
Proxy的handler是: ReflectiveFeign.FeignInvocationHandler
handler 持有的dispatch是:SynchronousMethodHandler
target是:HardCodedTarget
client是:LoadBalancerFeignClient

我们看下handler的源码

static class FeignInvocationHandler implements InvocationHandler {
    //要执行的对象
    private final Target target;
    //方法和SynchronousMethodHandler的映射集合
    private final Map<Method, MethodHandler> dispatch;
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       //具体执行的的是dispatch的invoke
       return dispatch.get(method).invoke(args);
    }
}
final class SynchronousMethodHandler implements MethodHandler {
  public Object invoke(Object[] argv) throws Throwable {
    //构建一个RequestTemplate由ReflectiveFeign.BuildEncodedTemplateFromArgs,主要是解析
    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) {
        }
        continue;
      }
    }
  }
  Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
    //执行所有RequestInterceptor并构建一个Request对象
    Request request = targetRequest(template);
    Response response;
    long start = System.nanoTime();
    try {
      //client是LoadBalancerFeignClient,我们看下源码
      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) {
      throw errorExecuting(request, e);
    }
    long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);

    CompletableFuture<Object> resultFuture = new CompletableFuture<>();
    asyncResponseHandler.handleResponse(resultFuture, metadata.configKey(), response,
        metadata.returnType(),elapsedTime);
    return resultFuture.join();
  }
  Request targetRequest(RequestTemplate template) {
    //遍历所有的拦截器并执行
    for (RequestInterceptor interceptor : requestInterceptors) {
      interceptor.apply(template);
    }
    //最终在return Request.create(this.method, this.url(), this.headers(), this.body, this);
    return target.apply(template);
  }
}
public final class RequestTemplate implements Serializable {
  public Request request() {
    if (!this.resolved) {
      throw new IllegalStateException("template has not been resolved.");
    }
    return Request.create(this.method, this.url(), this.headers(), this.body, this);
  }
}
public class LoadBalancerFeignClient implements Client {
  public Response execute(Request request, Request.Options options) throws IOException {
    try {
      URI asUri = URI.create(request.url());
      String clientName = asUri.getHost();
      URI uriWithoutHost = cleanUrl(request.url(), clientName);
      //构建RibbonRequest
      FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
          this.delegate, request, uriWithoutHost);
      // 获取配置信息
      IClientConfig requestConfig = getClientConfig(options, clientName);
      //找到
      return lbClient(clientName).executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();
    }
  }
  private FeignLoadBalancer lbClient(String clientName) {
    return this.lbClientFactory.create(clientName);
  }
}

public class CachingSpringLoadBalancerFactory {
  public FeignLoadBalancer create(String clientName) {
    // 缓存有直接返回
    FeignLoadBalancer client = this.cache.get(clientName);
    if (client != null) {
      return client;
    }
    IClientConfig config = this.factory.getClientConfig(clientName);
    //获取ILoadBalancer实例
    ILoadBalancer lb = this.factory.getLoadBalancer(clientName);
    ServerIntrospector serverIntrospector = this.factory.getInstance(clientName,
        ServerIntrospector.class);
    //构建一个FeignLoadBalancer
    client = this.loadBalancedRetryFactory != null
        ? new RetryableFeignLoadBalancer(lb, config, serverIntrospector,
            this.loadBalancedRetryFactory)
        : new FeignLoadBalancer(lb, config, serverIntrospector);
    //缓存起来
    this.cache.put(clientName, client);
    return client;
  }
}

FeignLoadBalancer 继承了AbstractLoadBalancerAwareClient,最终executeWithLoadBalancer

public abstract class AbstractLoadBalancerAwareClient<S extends ClientRequest, T extends IResponse> extends LoadBalancerContext implements IClient<S, T>, IClientConfigAware {
    public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
        LoadBalancerCommand<T> command = buildLoadBalancerCommand(request, requestConfig);
        try {
            return command.submit(
                new ServerOperation<T>() {
                    @Override
                    public Observable<T> call(Server server) {
                        // 这个时候从注册中心里获取到了真实的调用url
                        URI finalUri = reconstructURIWithServer(server, request.getUri());
                        S requestForServer = (S) request.replaceUri(finalUri);
                        try {
                             //执行调用
                            return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));
                        } 
                        catch (Exception e) {
                            return Observable.error(e);
                        }
                    }
                })
                .toBlocking()
                .single();
        } catch (Exception e) {
            Throwable t = e.getCause();
            if (t instanceof ClientException) {
                throw (ClientException) t;
            } else {
                throw new ClientException(e);
            }
        }
    }
}

看下具体的执行流程

图片

至于怎么去做负载,后期再分析。

如果觉得对你有帮助,请关注公众号:5ycode,后续会不断更新哦

公众号图片

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值