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

Java中的Feign深入分析

 更新時(shí)間:2023年09月11日 11:33:07   作者:silmeweed  
這篇文章主要介紹了Java中的Feign深入分析,Feign是一個(gè)用于發(fā)送HTTP請(qǐng)求的工具,它的主要作用是在不同的服務(wù)之間傳遞Token,為了使用Feign,你需要在項(xiàng)目中配置一個(gè)Feign的配置類,需要的朋友可以參考下

一、使用方式:

1. java動(dòng)態(tài)生成 :

使用Feign.Builder動(dòng)態(tài)生成,可動(dòng)態(tài)靈活生成不同的操作對(duì)象。整個(gè)Feign操作核心就是生成這樣的Feign.Builder對(duì)象

1)示例:

GitHub github = Feign.builder()
           .decoder(new GsonDecoder())
           .logger(new Logger.JavaLogger().appendToFile("logs/http.log"))
           .logLevel(Logger.Level.FULL)
           .client(new OkHttpClient())
           .requestInterceptor(new ForwardedForInterceptor())
           .target(GitHub.class, https://api.github.com);

2)源代碼分析:

public abstract class Feign {
//1. Feign.Builder屬性。
public static class Builder {
  private final List<RequestInterceptor> requestInterceptors = new ArrayList<RequestInterceptor>();
  private Logger.Level logLevel = Logger.Level.NONE;
  private Contract contract = new Contract.Default(); //使用約解釋api標(biāo)注
  private Client client = new Client.Default(null, null);//網(wǎng)絡(luò)請(qǐng)求客戶端(okHttp/ApacheHttpClient)
  private Retryer retryer = new Retryer.Default();
  private Logger logger = new NoOpLogger();
  private Encoder encoder = new Encoder.Default();
  private Decoder decoder = new Decoder.Default();
  private QueryMapEncoder queryMapEncoder = new QueryMapEncoder.Default();
  private ErrorDecoder errorDecoder = new ErrorDecoder.Default();
  private Options options = new Options(); //
  private InvocationHandlerFactory invocationHandlerFactory = new InvocationHandlerFactory.Default();
  private boolean decode404;
  private boolean closeAfterDecode = true;
}
}
//2. 網(wǎng)絡(luò)請(qǐng)求客戶端的參數(shù)設(shè)置:(連接時(shí)間、讀取超過)
public static class Options {
    private final int connectTimeoutMillis;
    private final int readTimeoutMillis;
    private final boolean followRedirects;
}

2. Spring Feign注解方式實(shí)現(xiàn)

通過注解方式提高生成Feign.Bulder的效率,簡化代碼。其核心最終還是生成不同的Feign.Builder實(shí)例對(duì)象。(見1. java動(dòng)態(tài)生成 )在Spring cloud應(yīng)用中,當(dāng)我們要使用feign客戶端時(shí),一般要做以下三件事情 :

  • 使用注解@EnableFeignClients啟用feign客戶端: 掃描和注冊(cè)feign客戶端bean定義
  • 使用注解@FeignClient 定義feign客戶端 : 定義了一個(gè)feign客戶端.
  • 使用注解@Autowired使用上面所定義feign的客戶端 : 使用所定義feign的客戶端。 

示例:

//1.使用注解@EnableFeignClients啟用feign客戶端。
@SpringBootApplication
@EnableFeignClients(basePackages= {"com.missuteam.onepiece.oauth.api"},
defaultConfiguration = defaultFeignConfig.class)
public class TestApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
}
//2.FeignClient定義
@FeignClient(name = "choppe-oauth-server",
        configuration = AuthServiceFeignConfig.class,
        fallbackFactory = AuthServiceFallbackFactory.class,
        path = "/authCenter",
        decode404 = true)
public interface AuthServiceFeignClient {
    //接口
   @RequestMapping(value = "/echo", method = RequestMethod.GET)
    TestModel echo(@RequestParam("parameter") String parameter);
}

二、源代碼分析:

啟動(dòng)流程

1. 注冊(cè)所有feign客戶端的缺省配置@EnableFeignClients里指定的defaultConfiguration,生成一個(gè)FeignClientSpecification bean.

2. 注冊(cè)所有@FeignClient的configuration,生成一個(gè)配置FeignClientSpecification bean.

3. 所有的配置放置到FeignContext Bean里。

public class FeignAutoConfiguration {
   @Autowired(required = false)
   private List<FeignClientSpecification> configurations = new ArrayList<>();
   @Bean
   public FeignContext feignContext() {
      FeignContext context = new FeignContext();
      context.setConfigurations(this.configurations);
      return context;
   }
}

4. 生成@FeignClient的代理Bean,(FeignClientFactoryBean)FeignClientFactoryBean包括一個(gè)Fegin。

5. 配置FeignClientFactoryBean的屬性,可以從@EnableFeign里的defaultConfigure和各個(gè)@FeignClient里的configure,或application.yml配置屬性獲取。( feign.client.defaultToProperties = true yml里的配置(default和對(duì)應(yīng)的name)將覆蓋@EnableFeign和@FeignClient里的configure.)

protected void configureFeign(FeignContext context, Feign.Builder builder) {
   1.獲取application.yml里的配置信息。
   FeignClientProperties properties = applicationContext.getBean(FeignClientProperties.class);
   if (properties != null) {
      2.如果設(shè)置isDefaultToProperties=true,將使用application.yml里的default配置覆蓋@FeignClient或@EnableFeignClient里的defaultConfigure.
      if (properties.isDefaultToProperties()) {
         configureUsingConfiguration(context, builder);
         2.1@EnableFeignClient里的defaultConfigure.               
    configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
        2.2@FeignClient里的Configure.
         configureUsingProperties(properties.getConfig().get(this.name), builder);
      } else {
         configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
         configureUsingProperties(properties.getConfig().get(this.name), builder);
         configureUsingConfiguration(context, builder);
      }
   } else {
      configureUsingConfiguration(context, builder);
   }
}
protected void configureUsingConfiguration(FeignContext context, Feign.Builder builder) {
   Logger.Level level = getOptional(context, Logger.Level.class);
   if (level != null) {
      builder.logLevel(level);
   }
   Retryer retryer = getOptional(context, Retryer.class);
   if (retryer != null) {
      builder.retryer(retryer);
   }
   ErrorDecoder errorDecoder = getOptional(context, ErrorDecoder.class);
   if (errorDecoder != null) {
      builder.errorDecoder(errorDecoder);
   }
   Request.Options options = getOptional(context, Request.Options.class);
   if (options != null) {
      builder.options(options);
   }
   Map<String, RequestInterceptor> requestInterceptors = context.getInstances(
         this.name, RequestInterceptor.class);
   if (requestInterceptors != null) {
      builder.requestInterceptors(requestInterceptors.values());
   }
   if (decode404) {
      builder.decode404();
   }
}
protected void configureUsingProperties(FeignClientProperties.FeignClientConfiguration config, Feign.Builder builder) {
   if (config == null) {
      return;
   }
   if (config.getLoggerLevel() != null) {
      builder.logLevel(config.getLoggerLevel());
   }
   if (config.getConnectTimeout() != null && config.getReadTimeout() != null) {
      builder.options(new Request.Options(config.getConnectTimeout(), config.getReadTimeout()));
   }
   if (config.getRetryer() != null) {
      Retryer retryer = getOrInstantiate(config.getRetryer());
      builder.retryer(retryer);
   }
   if (config.getErrorDecoder() != null) {
      ErrorDecoder errorDecoder = getOrInstantiate(config.getErrorDecoder());
      builder.errorDecoder(errorDecoder);
   }
   if (config.getRequestInterceptors() != null && !config.getRequestInterceptors().isEmpty()) {
      // this will add request interceptor to builder, not replace existing
      for (Class<RequestInterceptor> bean : config.getRequestInterceptors()) {
         RequestInterceptor interceptor = getOrInstantiate(bean);
         builder.requestInterceptor(interceptor);
      }
   }
   if (config.getDecode404() != null) {
      if (config.getDecode404()) {
         builder.decode404();
      }
   }
   if (Objects.nonNull(config.getEncoder())) {
      builder.encoder(getOrInstantiate(config.getEncoder()));
   }
   if (Objects.nonNull(config.getDecoder())) {
      builder.decoder(getOrInstantiate(config.getDecoder()));
   }
   if (Objects.nonNull(config.getContract())) {
      builder.contract(getOrInstantiate(config.getContract()));
   }
}

FeignClientsRegistrar.class

//注冊(cè)All feign 默認(rèn)配置
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
      BeanDefinitionRegistry registry) {
   registerDefaultConfiguration(metadata, registry);
   registerFeignClients(metadata, registry);
}
// 注冊(cè)feign客戶端的缺省配置,缺省配置信息來自注解元數(shù)據(jù)的屬性 defaultConfiguration    
    private void registerDefaultConfiguration(AnnotationMetadata metadata,BeanDefinitionRegistry registry) {
        // 獲取注解@EnableFeignClients的注解屬性     
        Map<String, Object> defaultAttrs = metadata
                .getAnnotationAttributes(EnableFeignClients.class.getName(), true);
        if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
            String name;
            // 下面是對(duì)所注冊(cè)的缺省配置的的命名,格式如下 :
            // default.xxx.TestApplication
            if (metadata.hasEnclosingClass()) {
                //  針對(duì)注解元數(shù)據(jù)metadata對(duì)應(yīng)一個(gè)內(nèi)部類或者方法返回的方法本地類的情形
                name = "default." + metadata.getEnclosingClassName();
            }
            else {        
                // name 舉例 : default.xxx.TestApplication
                // 這里 xxx.TestApplication 是注解@EnableFeignClients所在配置類的長名稱           
                name = "default." + metadata.getClassName();
            }
            registerClientConfiguration(registry, name,
                    defaultAttrs.get("defaultConfiguration"));
        }
    }

 FeignClientFactoryBean.java封裝了,如何生成Feign

class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean,
      ApplicationContextAware {
   private Class<?> type;
   private String name;
   private String url;
   private String path;
   private boolean decode404;
   private ApplicationContext applicationContext;
   private Class<?> fallback = void.class;
   private Class<?> fallbackFactory = void.class;
   1.Feign.Builder
   protected Feign.Builder feign(FeignContext context) {
      FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
      Logger logger = loggerFactory.create(this.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);
      return builder;
   }
   2. 配置Feign.Builder
   protected void configureFeign(FeignContext context, Feign.Builder builder) {
      FeignClientProperties properties = applicationContext.getBean(FeignClientProperties.class);
      if (properties != null) {
         if (properties.isDefaultToProperties()) {
            configureUsingConfiguration(context, builder);
            configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
            configureUsingProperties(properties.getConfig().get(this.name), builder);
         } else {
            configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
            configureUsingProperties(properties.getConfig().get(this.name), builder);
            configureUsingConfiguration(context, builder);
         }
      } else {
         configureUsingConfiguration(context, builder);
      }
   }
3.最終生成Targeter
<T> T getTarget() {
   FeignContext context = applicationContext.getBean(FeignContext.class);
   Feign.Builder builder = feign(context);
   if (!StringUtils.hasText(this.url)) {
      String url;
      if (!this.name.startsWith("http")) {
         url = "http://" + this.name;
      }
      else {
         url = this.name;
      }
      url += cleanPath();
      return (T) loadBalance(builder, context, new HardCodedTarget<>(this.type,
            this.name, 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) {
         // 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 (T) targeter.target(this, builder, context, new HardCodedTarget<>(
         this.type, this.name, url));
}

EnableFeignClients類:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
   /**
    * 指定掃描的包或類,不指定時(shí),全部掃描.
    */
   String[] value() default {};
   String[] basePackages() default {};
   Class<?>[] basePackageClasses() default {};
   Class<?>[] clients() default {};
   /**
    * 用戶定義一個(gè)默認(rèn)的配置類,作用于所有FeignClient
    */
   Class<?>[] defaultConfiguration() default {};
}

到此這篇關(guān)于Java中的Feign深入分析的文章就介紹到這了,更多相關(guān)Feign深入分析內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java Optional優(yōu)雅處理空指針異常的實(shí)現(xiàn)步驟

    Java Optional優(yōu)雅處理空指針異常的實(shí)現(xiàn)步驟

    本文主要介紹了Java Optional 詳解:優(yōu)雅處理空指針異常,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2026-04-04
  • Java HttpClient技術(shù)詳解

    Java HttpClient技術(shù)詳解

    Http協(xié)議的重要性相信不用我多說了,HttpClient相比傳統(tǒng)JDK自帶的URLConnection,增加了易用和靈活性(具體區(qū)別,日后我們?cè)儆懻摚粌H是客戶端發(fā)送Http請(qǐng)求變得容易,而且也方便了開發(fā)人員測試接口(基于Http協(xié)議的),即提高了開發(fā)的效率,也方便提高代碼的健壯性
    2021-10-10
  • SpringSecurity OAuth2單點(diǎn)登錄和登出的實(shí)現(xiàn)

    SpringSecurity OAuth2單點(diǎn)登錄和登出的實(shí)現(xiàn)

    本文主要介紹了SpringSecurity OAuth2單點(diǎn)登錄和登出的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • JDK8升級(jí)JDK17過程中踩到的一些坑

    JDK8升級(jí)JDK17過程中踩到的一些坑

    這篇文章主要給大家介紹了關(guān)于JDK8升級(jí)JDK17過程中踩到的一些坑,對(duì)于一些老的項(xiàng)目,升級(jí)到JDK8則存在一些兼容性問題,是否升級(jí)需要酌情考慮,需要的朋友可以參考下
    2023-07-07
  • springcloud使用consul作為配置中心

    springcloud使用consul作為配置中心

    這篇文章主要介紹了springcloud使用consul作為配置中心,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-06-06
  • Spring?boot?Jpa添加對(duì)象字段使用數(shù)據(jù)庫默認(rèn)值操作

    Spring?boot?Jpa添加對(duì)象字段使用數(shù)據(jù)庫默認(rèn)值操作

    這篇文章主要介紹了Spring?boot?Jpa添加對(duì)象字段使用數(shù)據(jù)庫默認(rèn)值操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 解讀@NotNull和@NonNull的區(qū)別及使用

    解讀@NotNull和@NonNull的區(qū)別及使用

    這篇文章主要介紹了解讀@NotNull和@NonNull的區(qū)別及使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。
    2023-01-01
  • java中關(guān)于命令執(zhí)行匯總

    java中關(guān)于命令執(zhí)行匯總

    這篇文章主要介紹了java中關(guān)于命令執(zhí)行匯總,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • java中線程的狀態(tài)學(xué)習(xí)筆記

    java中線程的狀態(tài)學(xué)習(xí)筆記

    在本文里我們給大家整理了關(guān)于java中線程的狀態(tài)的相關(guān)知識(shí)點(diǎn)內(nèi)容,對(duì)此有需要的朋友們學(xué)習(xí)參考下。
    2019-03-03
  • SpringBoot通過Nginx代理獲取真實(shí)IP

    SpringBoot通過Nginx代理獲取真實(shí)IP

    springboot作為后臺(tái)代碼,獲取到的登錄IP是前臺(tái)的代理服務(wù)器地址,并不是用戶的真實(shí)IP地址,本文主要介紹了SpringBoot通過Nginx代理獲取真實(shí)IP,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01

最新評(píng)論

娄底市| 离岛区| 灵川县| 土默特右旗| 昌黎县| 含山县| 上栗县| 溆浦县| 周口市| 南陵县| 栖霞市| 鸡西市| 禄劝| 申扎县| 万山特区| 康平县| 宽城| 古浪县| 黔江区| 泉州市| 濮阳县| 兴和县| 措勤县| 新乡市| 石林| 竹山县| 三门县| 喀什市| 嘉兴市| 南投县| 泗阳县| 成都市| 石景山区| 仁化县| 唐海县| 安徽省| 金堂县| 深水埗区| 宝应县| 萨嘎县| 荃湾区|