0406-服務注冊與發現-客戶端feign-使用、配置、日志、timeout


官方地址:https://cloud.spring.io/spring-cloud-static/Edgware.SR3/single/spring-cloud.html#spring-cloud-feign

一、概述

  Feign是一個聲明式Web服務客戶端。它使編寫Web服務客戶端變得更容易。使用Feign創建一個接口並對其進行注釋。它具有可插入的注釋支持,包括Feign注釋和JAX-RS注釋。Feign還支持可插拔編碼器和解碼器。 Spring Cloud添加了對Spring MVC注釋的支持,並且使用了Spring Web中默認使用的相同HttpMessageConverters。Spring Cloud將Ribbon和Eureka集成在一起,在使用Feign時提供負載均衡的http客戶端。

  注意:JAX-RSJAX-WS

  源碼地址:https://github.com/OpenFeign/feign

1.1、基礎使用

1》添加pom

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2》啟動類上添加注解

@SpringBootApplication
@EnableFeignClients public class ComsumerMovieFeignApplication {
    public static void main(String[] args) {
        SpringApplication.run(ComsumerMovieFeignApplication.class, args);
    }
}

3》添加一個接口並為接口添加注解,調用用戶服務

@FeignClient("microservice-provider-user")
public interface UserFeignClient {
    // @GetMapping("/sample/{id}")
    @RequestMapping(method = RequestMethod.GET, value = "/movie/{id}")
    public User findById(@PathVariable("id") Long id);
}

注意點:1、spring注解不能使用getMapping,需使用RequestMapping;2、@PathVariable必須添加參數;3、當服務接受參數是一個對象時候,此時默認會轉化為post請求,及時接口寫的是get請求【?待解決】

    //請求不會成功,只要參數是復雜對象,即使指定了GET方法,feign依然會以post方法進行發送
    @RequestMapping(method = RequestMethod.GET, value = "/get-user")
    public User getUser(User user);

4》程序調用

    @Autowired
    private UserFeignClient userFeignClient;

    @GetMapping("/movie/{id}")
    public User findById(@PathVariable Long id) {
        return userFeignClient.findById(id);
    }

執行post類似

參考代碼:https://github.com/bjlhx15/spring-cloud/tree/master/microservice-comsumer-movie-feign

1.2、覆寫Feign的默認配置

1.2.1、概述

  Spring Cloud的Feign支持中的一個中心概念是指定的客戶端。

  每個feign客戶端都是整體的一部分,這些組件是一起工作以根據需要聯系遠程服務器,並且該組件具有一個名稱,開發人員可以使用@FeignClient批注命名。

  Spring Cloud使用FeignClientsConfiguration創建一個新的集合,作為每個指定客戶端的ApplicationContext。這包含(除其他外)feign.Decoder,feign.Encoder和feign.Contract。

  通過使用@FeignClient聲明額外配置(在FeignClientsConfiguration之上),Spring Cloud可讓您完全控制客戶端

示例

@FeignClient(name = "stores", configuration = FooConfiguration.class)
public interface StoreClient {
    //..
}

  注意事項:FooConfiguration 同RibbonConfiguration一致放包問題,參看:http://www.cnblogs.com/bjlhx/p/8859088.html

  注意事項2:以前使用url可以不用,現在必須使用name

1.2.2、默認配置

Spring Cloud Netflix默認提供以下bean for feign(BeanType beanName:ClassName):

  • Decoder feignDecoder: ResponseEntityDecoder (which wraps a SpringDecoder) 默認解碼
  • Encoder feignEncoder: SpringEncoder 默認編碼
  • Logger feignLogger: Slf4jLogger 默認日志
  • Contract feignContract: SpringMvcContract 默認契約
  • Feign.Builder feignBuilder: HystrixFeign.Builder 默認構建builder
  • Client feignClient: if Ribbon is enabled it is a LoadBalancerFeignClient, otherwise the default feign client is used.  默認client

  通過將feign.okhttp.enabled或feign.httpclient.enabled分別設置為true並將它們放在類路徑中,可以使用OkHttpClient和ApacheHttpClient feign客戶端。當使用Apache或OkHttpClient使用OK HTTP時,可以通過提供ClosableHttpClient的bean來定制HTTP客戶端。

1.2.3、非默認配置

  Spring Cloud Netflix默認情況下不提供以下bean,但仍從應用程序上下文中查找這些類型的bean以創建假客戶端:

  • Logger.Level
  • Retryer
  • ErrorDecoder
  • Request.Options
  • Collection<RequestInterceptor>
  • SetterFactory

1.2.4、開發

編寫一個默認注解

@Configuration
public class Configuration1 {
    @Bean
    public Contract feignContract() {
        return new feign.Contract.Default();
    }
}

  因為原默認注解使用spring的現在這里改用feign契約,故以下調用需要使用feign的注解RequestLine等

編寫客戶端調用

@FeignClient(name = "microservice-provider-user", configuration = Configuration1.class)
public interface UserFeignClient {
    @RequestLine("GET /sample/{id}")
    public User findById(@Param("id") Long id);
}

程序使用即可。

參看代碼:https://github.com/bjlhx15/spring-cloud/tree/master/microservice-comsumer-movie-feign-customizing

1.2.5、如果請求eureka的接口如

@FeignClient(name = "xxxx", url = "http://localhost:8761/", configuration = Configuration2.class)
public interface FeignClient2 {
    @RequestMapping(value = "/eureka/apps/{serviceName}")
    public String findServiceInfoFromEurekaByServiceName(@PathVariable("serviceName") String serviceName);
}

因為eureka設置了權限此時訪問失敗

需增加配置類,Configuration2增加權限校驗

@Configuration
public class Configuration2 {
    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
        return new BasicAuthRequestInterceptor("user", "a123");
    }
}

1.2.6、Feign請求/響應壓縮

feign.compression.request.enabled=true
feign.compression.response.enabled=true

Feign請求壓縮為您提供了類似於您為Web服務器設置的設置:

feign.compression.request.enabled=true
feign.compression.request.mime-types=text/xml,application/xml,application/json
feign.compression.request.min-request-size=2048

這些屬性使您可以選擇壓縮媒體類型和最小請求閾值長度。

 1.3、feign日志

  為每個創建的Feign客戶端創建一個記錄器。默認情況下,記錄器的名稱是用於創建Feign客戶端的接口的完整類名稱。 Feign日志記錄僅響應DEBUG級別。

application.yml. 

logging.level.project.user.UserClient: DEBUG

注level是具體類路徑。可能不生效,需要配置一下配置

您可以為每個客戶端配置的Logger.Level對象告訴Feign要記錄多少。選擇是:

  • NONE, No logging (DEFAULT).
  • BASIC, 只記錄請求方法和URL以及響應狀態碼和執行時間。
  • HEADERS, 記錄基本信息以及請求和響應標頭。
  • FULL, 為請求和響應記錄標題,正文和元數據。

例如,以下操作將Logger.Level設置為FULL:

@Configuration
public class FooConfiguration {
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

參看代碼:https://github.com/bjlhx15/spring-cloud/tree/master/microservice-comsumer-movie-feign-customizing

1.4、Feign第一次啟動timeout問題

  hystrix默認1秒超時

方法一、可配置超時時間增加:

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000

方法二、關閉熔斷超時

hystrix.command.default.execution.timeout.enabled: false

方法三、關閉熔斷機制

feign.hystrix.enabled: false

可以參看:https://github.com/Netflix/Hystrix/wiki/Configuration

1.5、手動創建Feign客戶端

@Import(FeignClientsConfiguration.class)
class FooController {

    private FooClient fooClient;

    private FooClient adminClient;

        @Autowired
    public FooController(Decoder decoder, Encoder encoder, Client client, Contract contract) {
        this.fooClient = Feign.builder().client(client)
                .encoder(encoder)
                .decoder(decoder)
                .contract(contract)
                .requestInterceptor(new BasicAuthRequestInterceptor("user", "user"))
                .target(FooClient.class, "http://PROD-SVC");

        this.adminClient = Feign.builder().client(client)
                .encoder(encoder)
                .decoder(decoder)
                .contract(contract)
                .requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin"))
                .target(FooClient.class, "http://PROD-SVC");
    }
}
View Code

1.6、feign源碼實現過程

1、首先通過@EnabledFeignClients注解開啟FeignClient的功能。主要是啟動程序時開啟對@FeignClient注解的包掃描

2、根據feign的規則實現接口,並在接口上面加上@FeignClient注解

3、程序啟動后,進行包掃描,掃描所有的@FeignClient的注解的類,並將這些類放入Ioc容器。

4、當接口的方法被調用時,通過JDK的代理來生成具體的RequestTemplate模板對象

5、根據RequestTemplate再生成Http請求的Request對象。

6、Request對象交給Client去處理,其中Client的網絡請求框架可以是HttpURLConnetion,HTTPClient和OkHttp等

7、最后Client被封裝到LoadBlanceClient類,這個類結合類Ribbon做負載均衡。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM