• Feign实战-Springboot集成OpenFeign Demo以及参数详解


    最近整理一下微服务的文章,先拿一直用的OpenFeign开刀

    思考:微服务之间如何方便优雅的实现服务间的远程调用

    一、说说openFeign是什么吧?

    说到这个,那不得不先说说RPC

    1.什么是RPC

    RPC 全称是 Remote Procedure Call ,即远程过程调用,其对应的是我们的本地调用。RPC 的目的是:让我们调用远程方法像调用本地方法一样

    1. //本地调用
    2. R result = orderService.findOrderByUserId(id);
    3. //RPC远程调用 orderService为代理对象
    4. R result = orderService.findOrderByUserId(id);

     

    RPC框架设计架构

    2. 什么是Feign

    Feign是Netflix开发的声明式、模板化的HTTP客户端,Feign可帮助我们更加便捷、优雅地调用HTTP API。

    Feign可以做到使用 HTTP 请求远程服务时就像调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个 HTTP 请求。它像 Dubbo 一样,consumer 直接调用接口方法调用 provider,而不需要通过常规的 Http Client 构造请求再解析返回数据。它解决了让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细节,更无需关注分布式环境开发。

    Spring Cloud openfeign对Feign进行了增强,使其支持Spring MVC注解,另外还整合了Ribbon和Eureka,从而使得Feign的使用更加方便。

    2.1 OpenFeign和Feign的区别

    Feign

    Feign是SpringCloud组件中的一个轻量级RESTful的Http服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。

    OpenFeign

    OpenFeign是SpringCloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

     

    2.2 Ribbon&Feign对比

    Ribbon+RestTemplate进行微服务调用

    1. @Bean
    2. @LoadBalanced
    3. public RestTemplate restTemplate() {
    4. return new RestTemplate();
    5. }
    6. //调用方式
    7. String url = "http://mall-order/order/findOrderByUserId/"+id;
    8. R result = restTemplate.getForObject(url,R.class);

    Feign进行微服务调用

    1. @FeignClient(value = "mall-order",path = "/order")
    2. public interface OrderFeignService {
    3. @RequestMapping("/findOrderByUserId/{userId}")
    4. public R findOrderByUserId(@PathVariable("userId") Integer userId);
    5. }
    6. //调用
    7. @Autowired
    8. OrderFeignService orderFeignService;
    9. //feign调用
    10. R result = orderFeignService.findOrderByUserId(id);

    2.3 Feign的设计架构 

    二、Spring Cloud Alibaba快速整合Feign

    下面是Springboot集成OpenFeign Demo,完全照着来妥妥的没问题

    服务提供者我就不写了,这就是正常的controller,主要是调用者这块,接下来写的也是这个

    1.在pom.xml文件中添加以下依赖

    1. <dependency>
    2. <groupId>org.springframework.cloudgroupId>
    3. <artifactId>spring-cloud-starter-openfeignartifactId>
    4. dependency>

    2.调用端添加启动注解 @EnableFeignClients

    1. @EnableAsync
    2. @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, DruidDataSourceAutoConfigure.class })
    3. @EnableDiscoveryClient
    4. @EnableFeignClients //扫描和注册feign客户端的beanDefinition
    5. @MapperScan("com.**.**.**.**.mapper")
    6. public class Application {
    7. public static void main(String[] args) {
    8. SpringApplication.run(Application.class, args);
    9. }
    10. }

    3.编写调用接口+@FeignClient注解

    创建一个FeignClient接口,用于定义要调用的远程服务的方法:

    1. @FeignClient(value = "base-application", path = "/base")
    2. @RequestMapping("/api/testDemo")
    3. public interface OpenFeignBaseDemo {
    4. @PostMapping("/queryList")
    5. String queryList(@RequestBody JSONObject jsonObject);
    6. }

    在上面的代码中,我们使用@FeignClient注解指定了要调用的远程服务的名称。然后,我们定义了一个名为queryList的方法,并使用@PostMapping注解指定了要调用的远程服务的API路径。

    4.发起调用,像调用本地方式一样调用远程服务

    在其他类中使用OpenFeignBaseDemo 来调用远程服务的方法

    1. @RestController
    2. @RequestMapping("/openFeignDemo")
    3. public class OpenFeignControllerDemo {
    4. @Autowired
    5. private OpenFeignBaseDemo openFeignBase;
    6. @PostMapping(value = "/test", produces = { "application/json;charset=utf-8" })
    7. public ResponseEntity test(@RequestBody JSONObject jsonObject) {
    8. //feign调用
    9. String res = openFeignBase.queryList(jsonObject);
    10. return new ResponseEntity(res, HttpStatus.OK);
    11. }
    12. }

    5.结果预览

    启动两个工程,postmain调用 请求url :localhost:8088/server/openFeignDemo/test。

    6.这里我必须强调一下第3步这个参数设置的含义

    1. public @interface FeignClient {
    2. @AliasFor("name")
    3. String value() default "";
    4. String contextId() default "";
    5. @AliasFor("value")
    6. String name() default "";
    7. String qualifier() default "";
    8. String url() default "";
    9. boolean decode404() default false;
    10. Class[] configuration() default {};
    11. Class fallback() default void.class;
    12. Class fallbackFactory() default void.class;
    13. String path() default "";
    14. boolean primary() default true;
    15. }

    下面就对各个属性进行分析

    value、name
    value和name的作用一样,如果没有配置url那么配置的值将作为服务名称,用于服务发现。反之只是一个名称。

    contextId
    我们不想将所有的调用接口都定义在一个类中,有一种解决方案就是为每个Client手动指定不同的contextId,这样就不会冲突了。

    url
    url用于配置指定服务的地址,相当于直接请求这个服务,不经过Ribbon的服务选择。像调试等场景可以使用。

    decode404
    当调用请求发生404错误时,decode404的值为true,那么会执行decoder解码,否则抛出异常。

    configuration
    configuration是配置Feign配置类,在配置类中可以自定义Feign的Encoder、Decoder、LogLevel、Contract等。

    fallback
    定义容错的处理类,也就是回退逻辑,fallback的类必须实现Feign Client的接口,无法知道熔断的异常信息。

    fallbackFactory
    也是容错的处理,可以知道熔断的异常信息。

    path
    path定义当前FeignClient访问接口时的统一前缀,比如接口地址是/user/get, 如果你定义了前缀是user, 那么具体方法上的路径就只需要写/get 即可。

    primary
    primary对应的是@Primary注解,默认为true,官方这样设置也是有原因的。当我们的Feign实现了fallback后,也就意味着Feign Client有多个相同的Bean在Spring容器中,当我们在使用@Autowired进行注入的时候,不知道注入哪个,所以我们需要设置一个优先级高的,@Primary注解就是干这件事情的。

    qualifier
    qualifier对应的是@Qualifier注解,使用场景跟上面的primary关系很淡,一般场景直接@Autowired直接注入就可以了。

    7.报错解决

    如果遇到这样的错误:feign.RetryableException: Read timed out executing POST 

    可以做如下处理:yaml配置

    1. feign:
    2. client:
    3. config:
    4. default:
    5. connectTimeout: 1000
    6. readTimeout: 6000

    或者propertis配置

    1. feign.client.config.default.connect-timeout=20000
    2. feign.client.config.default.read-timeout=20000

    https://cloud.spring.io/spring-cloud-openfeign/reference/html/

  • 相关阅读:
    Canal1--搭建Canal监听数据库变化
    抖音seo优化排名源码搭建
    springBoot集成websocket实时消息推送
    高数笔记05:不定积分与定积分
    基于JAVA旅游网站计算机毕业设计源码+系统+mysql数据库+lw文档+部署
    【斗破年番】谣言不攻自破,萧潇造型曝光,制作进度已达中州,风尊者帅翻
    ISP代理是什么?双ISP是什么意思?
    YOLOV8模型改进-添加CBAM注意力机制
    【JavaScript】声明变量的关键字let、var、const和val的区别
    Leetcode2065-最大化一张图中的路径价值
  • 原文地址:https://blog.csdn.net/Alex_81D/article/details/133090893