最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring-cloud Feign 的深入理解

 更新時(shí)間:2019年02月11日 15:51:44   作者:Degaulle  
這篇文章主要介紹了Spring-cloud Feign 的深入理解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

feign的調(diào)用流程

讀取注解信息:EnableFeignClients-->FeignClientsRegistrar-->FeignClientFactoryBean
feigh流程:ReflectiveFeign-->Contract-->SynchronousMethodHandler
相關(guān)configuration:FeignClientsConfiguration,F(xiàn)eignAutoConfiguration,DefaultFeignLoadBalancedConfiguration,F(xiàn)eignRibbonClientAutoConfiguration(Ribbon)

在FeignClientsRegistrar中:

  @Override
  public void registerBeanDefinitions(AnnotationMetadata metadata,
      BeanDefinitionRegistry registry) {
    //注冊(cè)feign配置信息
    registerDefaultConfiguration(metadata, registry);
    //注冊(cè)feign client
    registerFeignClients(metadata, registry);
  }

  private void registerFeignClient(BeanDefinitionRegistry registry,
      AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
    String className = annotationMetadata.getClassName();
    //準(zhǔn)備注入FeignClientFactoryBean
    BeanDefinitionBuilder definition = BeanDefinitionBuilder
        .genericBeanDefinition(FeignClientFactoryBean.class);
    ...
  }

查看FeignClientFactoryBean:

  @Override
  public Object getObject() throws Exception {
    FeignContext context = applicationContext.getBean(FeignContext.class);
    //構(gòu)建Feign.Builder
    Feign.Builder builder = feign(context);
    //如果注解沒(méi)有指定URL
    if (!StringUtils.hasText(this.url)) {
      String url;
      if (!this.name.startsWith("http")) {
        url = "http://" + this.name;
      }
      else {
        url = this.name;
      }
      url += cleanPath();
      return loadBalance(builder, context, new HardCodedTarget<>(this.type,
          this.name, url));
    }
    //如果指定了URL
    if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
      this.url = "http://" + this.url;
    }
    String url = this.url + cleanPath();
    Client client = getOptional(context, Client.class);
    if (client != null) {
      if (client instanceof LoadBalancerFeignClient) {
        // 因?yàn)橹付薝RL且classpath下有Ribbon,獲取client的delegate(unwrap)
        // not load balancing because we have a url,
        // but ribbon is on the classpath, so unwrap
        client = ((LoadBalancerFeignClient)client).getDelegate();
      }
      builder.client(client);
    }
    Targeter targeter = get(context, Targeter.class);
    return targeter.target(this, builder, context, new HardCodedTarget<>(
        this.type, this.name, url));
  }
  
  protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
      HardCodedTarget<T> target) {
    //獲取Feign Client實(shí)例
    Client client = getOptional(context, Client.class);
    if (client != null) {
      builder.client(client);
      //DefaultTargeter或者HystrixTargeter
      Targeter targeter = get(context, Targeter.class);
      //調(diào)用builder的target,其中就調(diào)用了Feign的newInstance
      return targeter.target(this, builder, context, target);
    }

    throw new IllegalStateException(
        "No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");
  }

在FeignClientsConfiguration配置了Feign.Builder,prototype類型:

  @Bean
  @Scope("prototype")
  @ConditionalOnMissingBean
  public Feign.Builder feignBuilder(Retryer retryer) {
    return Feign.builder().retryer(retryer);
  }

Feign的Builder.build返回了一個(gè)ReflectiveFeign:

  public Feign build() {
   SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
     new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
                        logLevel, decode404);
   ParseHandlersByName handlersByName =
     new ParseHandlersByName(contract, options, encoder, decoder,
                 errorDecoder, synchronousMethodHandlerFactory);
   //ReflectiveFeign構(gòu)造參數(shù)
   //ParseHandlersByName作用是通過(guò)傳入的target返回代理接口下的方法的各種信息(MethodHandler)
   //Contract:解析接口的方法注解規(guī)則,生成MethodMetadata
   //Options:Request超時(shí)配置
   //Encoder:請(qǐng)求編碼器
   //Decoder:返回解碼器
   //ErrorDecoder:錯(cuò)誤解碼器
   //SynchronousMethodHandler.Factory是構(gòu)建SynchronousMethodHandler的工廠
   //Client:代表真正執(zhí)行HTTP的組件
   //Retryer:該組決定了在http請(qǐng)求失敗時(shí)是否需要重試
   //RequestInterceptor:請(qǐng)求前的攔截器
   //Logger:記錄日志組件,包含各個(gè)階段記錄日志的方法和留給用戶自己實(shí)現(xiàn)的log方法
   //Logger.Level:日志級(jí)別
   //decode404:處理404的策略,返回空還是報(bào)錯(cuò)
   //synchronousMethodHandlerFactory通過(guò)所有的信息去包裝一個(gè)synchronousMethodHandler,在調(diào)用invoke方法的時(shí)候執(zhí)行HTTP
   return new ReflectiveFeign(handlersByName, invocationHandlerFactory);
  }

在調(diào)用Feign.Builder的target的時(shí)候,調(diào)用了ReflectiveFeign.newInstance:

 /**
  * creates an api binding to the {@code target}. As this invokes reflection, care should be taken
  * to cache the result.
  */
 @SuppressWarnings("unchecked")
 @Override
 //接收Target參數(shù)(包含feign代理接口的類型class,名稱,http URL)
 public <T> T newInstance(Target<T> target) {
  //首先通過(guò)**ParseHandlersByName**解析出接口中包含的方法,包裝RequestTemplate,組裝成<name, MethodHandler>
  Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
  Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
  //接口default方法List
  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)));
   }
  }
  //InvocationHandlerFactory.Default()返回了一個(gè)ReflectiveFeign.FeignInvocationHandler對(duì)象,通過(guò)傳入的methodHandler map 調(diào)用目標(biāo)對(duì)象的對(duì)應(yīng)方法
  InvocationHandler handler = factory.create(target, methodToHandler);
  //生成JDK代理對(duì)象
  T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[]{target.type()}, handler);
  //綁定接口的默認(rèn)方法到代理對(duì)象
  for(DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
   defaultMethodHandler.bindTo(proxy);
  }
  return proxy;
 }

生成Feign代理對(duì)象的基本流程圖:

當(dāng)調(diào)用接口方法時(shí),實(shí)際上就是調(diào)用代理對(duì)象invoke方法:

 @Override
 public Object invoke(Object[] argv) throws Throwable {
  //工廠創(chuàng)建請(qǐng)求模版
  RequestTemplate template = buildTemplateFromArgs.create(argv);
  //每次克隆一個(gè)新的Retryer
  Retryer retryer = this.retryer.clone();
  while (true) {
   try {
    //這里調(diào)用實(shí)際的Feign client execute
    return executeAndDecode(template);
   } catch (RetryableException e) {
    //失敗重試
    retryer.continueOrPropagate(e);
    if (logLevel != Logger.Level.NONE) {
     logger.logRetry(metadata.configKey(), logLevel);
    }
    continue;
   }
  }
 }

在DefaultFeignLoadBalancedConfiguration里實(shí)例化了LoadBalancerFeignClient

  @Override
  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);
      //delegate這里是Client.Default實(shí)例,底層調(diào)用的是java.net原生網(wǎng)絡(luò)訪問(wèn)
      FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
          this.delegate, request, uriWithoutHost);

      IClientConfig requestConfig = getClientConfig(options, clientName);
      //executeWithLoadBalancer會(huì)根據(jù)ribbon的負(fù)載均衡算法構(gòu)建url,這里不展開
      return lbClient(clientName).executeWithLoadBalancer(ribbonRequest,
          requestConfig).toResponse();
    }
    catch (ClientException e) {
      IOException io = findIOException(e);
      if (io != null) {
        throw io;
      }
      throw new RuntimeException(e);
    }
  }

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java中LinkedList和ArrayList的效率分析

    Java中LinkedList和ArrayList的效率分析

    本文主要介紹了Java中LinkedList和ArrayList的效率分析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • 詳解Java中Method的Invoke方法

    詳解Java中Method的Invoke方法

    這篇文章主要介紹了詳解Java中Method的Invoke方法,需要的朋友可以參考下
    2017-10-10
  • Java?六類運(yùn)算符詳解

    Java?六類運(yùn)算符詳解

    這篇文章主要介紹了Java?六類運(yùn)算符,在?Java?語(yǔ)言中,運(yùn)算符有算數(shù)運(yùn)算符、關(guān)系運(yùn)算符、邏輯運(yùn)算符、賦值運(yùn)算符、字符串連接運(yùn)算符、條件運(yùn)算符,感興趣的朋友可以閱讀一下
    2023-03-03
  • SpringBoot中分頁(yè)插件PageHelper的使用詳解

    SpringBoot中分頁(yè)插件PageHelper的使用詳解

    分頁(yè)查詢是為了高效展示大量數(shù)據(jù),通過(guò)分頁(yè)將數(shù)據(jù)劃分為多個(gè)部分逐頁(yè)展示,原生方法需手動(dòng)計(jì)算數(shù)據(jù)起始行,而使用PageHelper插件則簡(jiǎn)化這一過(guò)程,本文給大家介紹SpringBoot中分頁(yè)插件PageHelper的使用,感興趣的朋友一起看看吧
    2024-09-09
  • java實(shí)現(xiàn)字符串排列組合問(wèn)題

    java實(shí)現(xiàn)字符串排列組合問(wèn)題

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)字符串排列組合問(wèn)題,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • Java中使用Jedis操作Redis的示例代碼

    Java中使用Jedis操作Redis的示例代碼

    本篇文章主要介紹了Java中使用Jedis操作Redis的示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下。
    2016-12-12
  • java實(shí)現(xiàn)超市商品庫(kù)存管理平臺(tái)

    java實(shí)現(xiàn)超市商品庫(kù)存管理平臺(tái)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)超市商品庫(kù)存管理平臺(tái),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • 輕松掌握J(rèn)ava享元模式

    輕松掌握J(rèn)ava享元模式

    這篇文章主要幫助大家輕松掌握J(rèn)ava享元模式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • java中MultipartFile互轉(zhuǎn)File的方法

    java中MultipartFile互轉(zhuǎn)File的方法

    本文主要介紹了java中MultipartFile互轉(zhuǎn)File的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Spring為什么要用三級(jí)緩存解決循環(huán)依賴呢

    Spring為什么要用三級(jí)緩存解決循環(huán)依賴呢

    本文主要介紹了Spring如何使用三級(jí)緩存解決循環(huán)依賴問(wèn)題,本文為了方便說(shuō)明,先設(shè)置兩個(gè)業(yè)務(wù)層對(duì)象,命名為AService和BService,結(jié)合示例給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2025-01-01

最新評(píng)論

富顺县| 中卫市| 喀喇沁旗| 浮山县| 云和县| 从化市| 织金县| 昂仁县| 大冶市| 灌云县| 萝北县| 哈密市| 五华县| 五寨县| 汉沽区| 奉节县| 寿光市| 武义县| 苏尼特左旗| 枣庄市| 玛曲县| 四会市| 辽源市| 百色市| 德化县| 巴彦淖尔市| 台中县| 德保县| 酉阳| 札达县| 延吉市| 台东县| 陆丰市| 盐池县| 金湖县| 巫山县| 克拉玛依市| 湟源县| 葵青区| 东海县| 乐平市|