欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中的Feign深入分析

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

一、使用方式:

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

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

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標注
  private Client client = new Client.Default(null, null);//網(wǎ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)絡請求客戶端的參數(shù)設置:(連接時間、讀取超過)
public static class Options {
    private final int connectTimeoutMillis;
    private final int readTimeoutMillis;
    private final boolean followRedirects;
}

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

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

  • 使用注解@EnableFeignClients啟用feign客戶端: 掃描和注冊feign客戶端bean定義
  • 使用注解@FeignClient 定義feign客戶端 : 定義了一個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);
}

二、源代碼分析:

啟動流程

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

2. 注冊所有@FeignClient的configuration,生成一個配置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包括一個Fegin。

5. 配置FeignClientFactoryBean的屬性,可以從@EnableFeign里的defaultConfigure和各個@FeignClient里的configure,或application.yml配置屬性獲取。( feign.client.defaultToProperties = true yml里的配置(default和對應的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.如果設置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

//注冊All feign 默認配置
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
      BeanDefinitionRegistry registry) {
   registerDefaultConfiguration(metadata, registry);
   registerFeignClients(metadata, registry);
}
// 注冊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;
            // 下面是對所注冊的缺省配置的的命名,格式如下 :
            // default.xxx.TestApplication
            if (metadata.hasEnclosingClass()) {
                //  針對注解元數(shù)據(jù)metadata對應一個內部類或者方法返回的方法本地類的情形
                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 {
   /**
    * 指定掃描的包或類,不指定時,全部掃描.
    */
   String[] value() default {};
   String[] basePackages() default {};
   Class<?>[] basePackageClasses() default {};
   Class<?>[] clients() default {};
   /**
    * 用戶定義一個默認的配置類,作用于所有FeignClient
    */
   Class<?>[] defaultConfiguration() default {};
}

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

相關文章

  • java中字符串替換常用的4種方法

    java中字符串替換常用的4種方法

    在Java中String類提供了許多方便的方法來處理字符串,下面這篇文章主要給大家介紹了關于java中字符串替換常用的4種方法,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-03-03
  • Lombok中關于@Data的使用解析

    Lombok中關于@Data的使用解析

    這篇文章主要介紹了Lombok中關于@Data的使用解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • SpringBoot自動裝配Import示例詳解

    SpringBoot自動裝配Import示例詳解

    SpringBoot中@Import注解的使用可以幫助開發(fā)者將指定的Bean或配置類導入到IOC容器中,該注解支持四種用法:導入Bean、導入配置類、實現(xiàn)ImportSelector接口和實現(xiàn),感興趣的朋友一起看看吧
    2024-09-09
  • java學習教程之常量折疊詳解

    java學習教程之常量折疊詳解

    這篇文章主要給大家介紹了關于java學習教程之常量折疊的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用java具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-09-09
  • springboot業(yè)務功能實戰(zhàn)之告別輪詢websocket的集成使用

    springboot業(yè)務功能實戰(zhàn)之告別輪詢websocket的集成使用

    WebSocket使得客戶端和服務器之間的數(shù)據(jù)交換變得更加簡單,允許服務端主動向客戶端推送數(shù)據(jù),下面這篇文章主要給大家介紹了關于springboot業(yè)務功能實戰(zhàn)之告別輪詢websocket的集成使用,需要的朋友可以參考下
    2022-10-10
  • Java SpringBoot快速集成SpringBootAdmin管控臺監(jiān)控服務詳解

    Java SpringBoot快速集成SpringBootAdmin管控臺監(jiān)控服務詳解

    這篇文章主要介紹了如何基于springboot-admin管控臺監(jiān)控服務,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2021-09-09
  • Java?Rabbitmq中四種集群架構的區(qū)別詳解

    Java?Rabbitmq中四種集群架構的區(qū)別詳解

    這篇文章主要為大家詳細介紹了Java?Rabbitmq中四種集群架構的區(qū)別,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • 解決springboot3:mybatis-plus依賴錯誤:org.springframework.beans.factory.UnsatisfiedDependencyException

    解決springboot3:mybatis-plus依賴錯誤:org.springframework.beans.fac

    這篇文章主要介紹了解決springboot3:mybatis-plus依賴錯誤:org.springframework.beans.factory.UnsatisfiedDependencyException問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • 新手初學Java對象內存構成

    新手初學Java對象內存構成

    這篇文章主要介紹了深入理解JVM之Java對象的創(chuàng)建、內存布局、訪問定位,結合實例形式詳細分析了Java對象的創(chuàng)建、內存布局、訪問定位相關概念、原理、操作技巧與注意事項,需要的朋友可以參考下
    2021-07-07
  • maven 打包項目的幾種方式

    maven 打包項目的幾種方式

    maven目前在web上面的使用方式很普遍,而打包的方式也存在很多方式,本文就詳細的介紹了三種方式,具有一定的參考價值,感興趣的可以了解下
    2021-06-06

最新評論