当前位置:   article > 正文

微服务之OpenFeigin

openfeigin

一:什么是Feign

1.1)Feign是Netflix开发的声明式、模板化的HTTP客户端,其灵感来自Retrofit、JAXRS­2.0以及WebSocket。Feign 可帮助我们更加便捷、优雅地调用HTTP API。

在Spring Cloud中,使用Feign非常简单——只需创建接口,并在接口上添加注解即可。 Feign支持多种注解,例如Feign自带的注解或者JAX­RS注解等。Spring Cloud对Feign进行了增强,使其支持Spring MVC注解,另外还整合了Ribbon和Eureka,从而使得Feign的使用更加方便

1.2)Ribbon Vs Feign

①:Ribbon+RestTemplate进行微服务调用 模式 ResponseEntity responseEntity = restTemplate.getForEntity("http://order-service/order/queryOrdersByUserId/"+userId,List.class);

  1. Ribbon进行调用
  2. @Bean
  3. @LoadBalanced
  4. public RestTemplate restTemplate() {
  5. return new RestTemplate();

缺点:

ResponseEntity responseEntity = restTemplate.getForEntity("http://orderservice/order/queryOrdersByUserId/"+userId,List.class); ①:我们不难发现,我们构建上诉的URL 是比较简单的,假如我们业务系统十分复杂,类似如下节点 https://www.baidu.com/s? wd=asf&rsv_spt=1&rsv_iqid=0xa25bbeba000047fd&issp=1&f=8&rsv_bp=0&rsv_idx=2&ie=utf8&tn=baiduhome_pg&rsv_enter=1&rsv_sug3=3&rsv_sug1=2&rsv_sug7=100&rsv_sug2=0&inputT=328&rsv_sug4=328 那么我们构建这个请求的URL是不是很复杂,若我们请求的参数有可能变动,那么是否这个URL是不是很复 杂

②: 如果系统业务非常复杂,而你是一个新人,当你看到这行代码,恐怕很难一眼看出其用途是什么!此时,你 很可能需要寻求老同事的帮助(往往是这行代码的作者,哈哈哈,可万一离职了呢?),或者查阅该目标地 址对应的文档(文档常常还和代码不匹配),才能清晰了解这行代码背后的含义!否则,你只能陷入蛋疼的 境地!

1.3)在我们工程中怎么添加Feign

1.3.1)我们采取开发中常用的套路 定义一个03-ms-alibaba-feign-api工程

①:第一步,引入依赖

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring‐cloud‐starter‐openfeign</artifactId>
  4. </dependency>

②:第二步:修改打包方式(因为该工程式一个普通的jar 不需要打可执行的jar)

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>org.apache.maven.plugins</groupId>
  5. <artifactId>maven‐jar‐plugin</artifactId>
  6. </plugin>
  7. </plugins>
  8. </build>

第三步:编写声明式接口

  1. @FeignClient(name = "product‐center")
  2. public interface ProductCenterFeignApi {
  3. /**
  4. * 声明式接口,远程调用http://product‐center/selectProductInfoById/{productNo}
  5. * @param productNo
  6. * @return
  7. */
  8. @RequestMapping("/selectProductInfoById/{productNo}")
  9. ProductInfo selectProductInfoById(@PathVariable("productNo") String productNo);
  10. }

1.3.2)调用者工程03-ms-alibaba-feign-order

第一步:引入依赖包 03-ms-alibaba-feign-api

  1. <dependency>
  2. <groupId>com.tuling</groupId>
  3. <artifactId>03‐ms‐alibaba‐feign‐api</artifactId>
  4. <version>0.0.1‐SNAPSHOT</version>
  5. </dependency>

第二步: 开启注解加入 @EnableFeignClients

  1. @SpringBootApplication
  2. @EnableDiscoveryClient
  3. @EnableFeignClients
  4. public class MsAlibabaFeignOrderApplication {
  5. public static void main(String[] args) {
  6. SpringApplication.run(Tulingvip03MsAlibabaFeignOrderApplication.class, args);
  7. }
  8. }

第三步:调用方式(像调用本地方式一样调用远程服务)

  1. @Autowired
  2. private ProductCenterFeignApi productCenterFeignApi;
  3. ProductInfo productInfo = productCenterFeignApi.selectProductInfoById(orderNo);

1.3.3)我们服务提供者ms-alibaba-feign-product 的controller 需要实现我们的productCenterFeignApi接口,防止修 改(比如我们的productCenterFeignApi修改了,若没有实现该接口,服务提供者感知不到)

第一步:引入依赖 ms-alibaba-feign-api

第二步:我们的ProductInfoController实现productCenterFeignApi接口

  1. @RestController
  2. public class ProductInfoController implements ProductCenterFeignApi

二:如何自定义Feign

2.1)默认情况下,Feign的调用不打印日志,我们需要通过自定义来打印我们的Feign的日志 (basic适 用于生产环境)

①: 我们在03-ms-alibaba-feign-api工程中添加Feign的自定义配置 

  1. /**
  2. * 这个类上千万不要添加@Configuration,不然会被作为全局配置文件共享
  3. *
  4. */
  5. public class ProductCenterFeignConfig {
  6. @Bean
  7. public Logger.Level level() {
  8. //return Logger.Level.FULL;
  9. return Logger.Level.BASIC;
  10. }
  11. }
  12. @FeignClient(name = "product‐center",configuration = ProductCenterFeignConfig.class)
  13. public interface ProductCenterFeignApi {
  14. /**
  15. * 声明式接口,远程调用http://product‐center/selectProductInfoById/{productNo}
  16. * @param productNo
  17. * @return
  18. */
  19. @RequestMapping("/selectProductInfoById/{productNo}")
  20. ProductInfo selectProductInfoById(@PathVariable("productNo") String productNo);
  21. }

②:针对调用端工程03-ms-alibaba-customcfg-feign-order针对日志com.demo.feignapi 包下的日志级 别必须调整为DEBUG级别的 不然是不会打印日志的

  1. logging:
  2. level:
  3. com:
  4. demo:
  5. feignapi: debug

2.2)基于yml文件细粒度配置

ProductCenterFeignApi 不用指定configuration的选项

  1. @FeignClient(name = "product‐center")
  2. public interface ProductCenterFeignApi {
  3. /**
  4. * 声明式接口,远程调用http://product‐center/selectProductInfoById/{productNo}
  5. * @param productNo
  6. * @return
  7. */
  8. @RequestMapping("/selectProductInfoById/{productNo}")
  9. ProductInfo selectProductInfoById(@PathVariable("productNo") String productNo);
  10. }

在调用方:03-ms-alibaba-customcfg-feign-order 通过feign:client:config:微服务名称:loggerLevel: 日志级别来指定

  1. logging:
  2. level:
  3. com:
  4. demo:
  5. feignapi: debug
  6. feign:
  7. client:
  8. config:
  9. product‐center:
  10. loggerLevel: full

2.3)使用Feign原生的注解配置(需要修改契约)

根据自动装配我们FeignClients的配置中的默认锲约是springmvc(也就是说支持SpingMvc注解)

  1. @Bean
  2. @ConditionalOnMissingBean
  3. public Contract feignContract(ConversionService feignConversionService) {
  4. return new SpringMvcContract(this.parameterProcessors, feignConversionService);
  5. }
  6. 所以我们在FeignClient上可以使用Mvc的注解
  7. @RequestMapping("/selectProductInfoById/{productNo}")
  8. ProductInfo selectProductInfoById(@PathVariable("productNo") String productNo);

现在我们需要想使用Feign的原生注解来标识方法需要修改锲约

  1. public class ProductCenterFeignConfig{
  2. /**
  3. * 根据SpringBoot自动装配FeignClientsConfiguration 的FeignClient的契约是SpringMvc
  4. *
  5. 通过修改契约为默认的Feign的锲约,那么就可以使用默认的注解
  6. * @return
  7. */
  8. @Bean
  9. public Contract feiContract() {
  10. return new Contract.Default();
  11. }
  12. }

FeignClient类ProductCenterFeignApi使用Feign原生的注解

  1. @FeignClient(name = "product‐center",configuration = ProductCenterFeignConfig.class)
  2. public interface ProductCenterFeignApi {
  3. /**
  4. * 修改锲约为Feign的 那么就可以使用默认的注解
  5. * @param productNo
  6. * @return
  7. */
  8. @RequestLine("GET /selectProductInfoById/{productNo}")
  9. ProductInfo selectProductInfoById(@Param("productNo") String productNo);
  10. }

2.4)拦截器的应用配置

  1. public class MyRequestInterceptor implements RequestInterceptor {
  2. @Override
  3. public void apply(RequestTemplate template) {
  4. template.header("token", UUID.randomUUID().toString());
  5. }
  6. }
  7. public class ProductCenterFeignConfig {
  8. @Bean
  9. public RequestInterceptor requestInterceptor() {
  10. return new MyRequestInterceptor();
  11. }
  12. }
  13. @FeignClient(name = "product‐center",configuration = ProductCenterFeignConfig.class)
  14. //@FeignClient(name = "product‐center")
  15. public interface ProductCenterFeignApi {
  16. @RequestLine("GET /getToken4Header")
  17. String getToken4Header(@RequestHeader("token") String token);
  18. }

服务提供者

  1. @RestController
  2. @Slf4j
  3. public class ProductInfoController implements ProductCenterFeignApi {
  4. @RequestMapping("/getToken4Header")
  5. public String getToken4Header(@RequestHeader("token") String token) {
  6. log.info("token:{}",token);
  7. return token;
  8. }
  9. }

2.4)Feign调用优化方案

第一步:开启连接池配置

  1. feign:
  2. client:
  3. config:
  4. product-center:
  5. loggerLevel: full
  6. contract: feign.Contract.Default
  7. httpclient:
  8. #让feign底层使用HttpClient去调用
  9. enabled: true
  10. max‐connections: 200 #最大连接数
  11. max‐connections‐per‐route: 50 #为每个url请求设置最大连接数

第二步:调整Feign的日志级别(强烈推荐使用Basic级别的)

2.5)Feign的生产实践 (以Feign的超时说了算) 问题

①:Feign的底层用的是Ribbon,那么我们怎么配置超时时间

服务提供方模拟耗时 睡眠3S

 

  1. 配置这个 ribbon肯定会超时
  2. ribbon:
  3. connectTimeout: 2000
  4. readTimeout: 2000
  5. (Feign不会超时)
  6. feign:
  7. client:
  8. config:
  9. default:
  10. connectTimeout: 5000
  11. readTimeout: 5000

正好调用是3S 说明以Feign的超时说了算

这种配置 Feign超时了

  1. ribbon:
  2. connectTimeout: 5000
  3. readTimeout: 5000
  4. http:
  5. client:
  6. enabled: true
  7. feign:
  8. client:
  9. config:
  10. default:
  11. connectTimeout: 2000
  12. readTimeout: 2000

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/1005797
推荐阅读
相关标签
  

闽ICP备14008679号