• Spring Cloud OpenFeign系列:简介和使用


    一、简介

    官网:https://spring.io/projects/spring-cloud-openfeign

    文档:https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/

    配置:https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/appendix.html

    OpenFeign是一个显示声明式的WebService客户端。使用OpenFeign能让编写Web Service客户端更加简单。使用时只需定义服务接口,然后在上面添加注解。OpenFeign也支持可拔插式的编码和解码器。spring cloud对feign进行了封装,使其支持MVC注解和HttpMessageConverts。和eureka(服务注册中心)和ribbon组合可以实现负载均衡。在Spring Cloud中使用OpenFeign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问HTTP请求,非常的方便。

    OpenFeign 具有负载均衡功能,其可以对指定的微服务采用负载均衡方式进行消费、访问。之前老版本 Spring Cloud 所集成的 OpenFeign 默认采用了 Ribbon 负载均衡器。但由于Netflix 已不再维护 Ribbon,所以从 Spring Cloud 2021.x 开始集成的 OpenFeign 中已彻底丢弃Ribbon,而是采用 Spring Cloud 自行研发的 Spring Cloud Loadbalancer 作为负载均衡器

    		<dependency>
    			<groupId>org.springframework.cloudgroupId>
    			<artifactId>spring-cloud-starter-openfeignartifactId>
    		dependency>
          
    		<dependency>
    			<groupId>org.springframework.cloudgroupId>
    			<artifactId>spring-cloud-starter-loadbalancerartifactId>
    		dependency>
    

    注意:负载均衡必须引入loadbalancer

    二、使用

    环境:

    jdk:17

    idea:2023.2

    spring-boot:3.0.2

    1、创建父工程

    引入坐标

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0modelVersion>
    
      <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>3.0.2version>
        <relativePath/> 
      parent>
    
      <groupId>com.mcodegroupId>
      <artifactId>openfeign-demoartifactId>
      <version>1.0-SNAPSHOTversion>
      <packaging>pompackaging>
      <name>openfeign-demoname>
      <url>http://maven.apache.orgurl>
    
      <properties>
        <java.version>17java.version>
        <spring-cloud.version>2022.0.0spring-cloud.version>
        <spring-cloud-alibaba.version>2022.0.0.0spring-cloud-alibaba.version>
      properties>
    
      <modules>
         <module>order-clientmodule>
         <module>order-servicemodule>
      modules>
    
      <dependencyManagement>
        <dependencies>
          <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-alibaba-dependenciesartifactId>
            <version>${spring-cloud-alibaba.version}version>
            <type>pomtype>
            <scope>importscope>
          dependency>
          <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-dependenciesartifactId>
            <version>${spring-cloud.version}version>
            <type>pomtype>
            <scope>importscope>
          dependency>
        dependencies>
      dependencyManagement>
      <build>
        <plugins>
          <plugin>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-maven-pluginartifactId>
          plugin>
        plugins>
      build>
    project>
    

    2、创建order-service模块

    导入坐标

    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0modelVersion>
        <parent>
            <groupId>com.mcodegroupId>
            <artifactId>openfeign-demoartifactId>
            <version>1.0-SNAPSHOTversion>
        parent>
    
        <artifactId>order-serviceartifactId>
        <version>0.0.1-SNAPSHOTversion>
        <name>order-servicename>
        <description>order-servicedescription>
    
        <properties>
            <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        properties>
        <dependencies>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
            dependency>
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <optional>trueoptional>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
            dependency>
        dependencies>
    project>
    

    配置application.yml

    
    spring:
      application:
        name: order-service
      cloud:
        nacos:
          discovery:
            username: nacos
            password: nacos
            server-addr: localhost:8848
    server:
      port: 8081
    

    配置启动类,启动Nacos注入

    package com.mcode.orderservice;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    @SpringBootApplication
    @EnableDiscoveryClient
    public class OrderServiceApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(OrderServiceApplication.class, args);
        }
    }
    

    添加Order类,用来测试

    package com.mcode.orderservice.bean;
    
    import lombok.Data;
    
    /**
     * ClassName: Order
     * Package: com.mcode.orderservice.bean
     * Description:
     *
     * @Author: robin
     * @Create: 2023/10/22 - 1:32 PM
     * @Version: v1.0
     */
    @Data
    public class Order {
        private Integer id;
        private String orderNo;
        private String productName;
    }
    

    添加OrderController控制器

    package com.mcode.orderservice.controller;
    
    import com.mcode.orderservice.bean.Order;
    import org.springframework.web.bind.annotation.*;
    
    /**
     * ClassName: OrderController
     * Package: com.mcode.orderservice.controller
     * Description:
     *
     * @Author: robin
     * @Create: 2023/10/22 - 1:31 PM
     * @Version: v1.0
     */
    @RestController
    @RequestMapping("/order")
    public class OrderController {
      
        //方便后面的负载均衡测试
        @Value("${server.port}")
        public int port;
      
        @GetMapping("/{id}")
        public Order getOrderById(@PathVariable("id") Integer id){
            Order order = new Order();
            order.setOrderNo("20201213");
            order.setProductName("商品名称 端口:" + port);
            order.setId(1);
            return order;
        }
    }
    

    3、创建order-client模块

    导入坐标

    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0modelVersion>
    	<parent>
    	     <groupId>com.mcodegroupId>
    		<artifactId>openfeign-demoartifactId>
    		<version>1.0-SNAPSHOTversion>
    	parent>
    
    	<artifactId>order-clientartifactId>
    	<version>0.0.1-SNAPSHOTversion>
    	<name>order-clientname>
    	<description>order-clientdescription>
    	<properties>
    		<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
    	properties>
    	<dependencies>
    		<dependency>
    			<groupId>com.alibaba.cloudgroupId>
    			<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
    		dependency>
    
    		<dependency>
    			<groupId>org.springframework.bootgroupId>
    			<artifactId>spring-boot-starter-webartifactId>
    		dependency>
    		<dependency>
    			<groupId>org.springframework.cloudgroupId>
    			<artifactId>spring-cloud-starter-openfeignartifactId>
    		dependency>
           
    		<dependency>
    			<groupId>org.springframework.cloudgroupId>
    			<artifactId>spring-cloud-starter-loadbalancerartifactId>
    		dependency>
    		<dependency>
    			<groupId>org.projectlombokgroupId>
    			<artifactId>lombokartifactId>
    			<optional>trueoptional>
    		dependency>
    		<dependency>
    			<groupId>org.springframework.bootgroupId>
    			<artifactId>spring-boot-starter-testartifactId>
    			<scope>testscope>
    		dependency>
    	dependencies>
    project>
    

    配置application.yml

    spring:
      application:
        name: order-client
      cloud:
        nacos:
          discovery:
            username: nacos
            password: nacos
            server-addr: localhost:8848
    server:
      port: 8080
    

    配置启动类,启动FeignClient和Nacos

    package com.mcode.orderclient;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    
    @SpringBootApplication
    @EnableFeignClients
    @EnableDiscoveryClient
    public class OrderClientApplication {
    
    	public static void main(String[] args) {
    		SpringApplication.run(OrderClientApplication.class, args);
    	}
    }
    

    添加Order类,用来测试

    package com.mcode.orderclient.bean;
    
    import lombok.Data;
    
    /**
     * ClassName: Order
     * Package: com.mcode.orderclient.bean
     * Description:
     *
     * @Author: robin
     * @Create: 2023/10/22 - 1:32 PM
     * @Version: v1.0
     */
    @Data
    public class Order {
        private Integer id;
        private String orderNo;
        private String productName;
    }
    

    添加OrderService,用来定义Feign接口

    package com.mcode.orderclient.service;
    
    import com.mcode.orderclient.bean.Order;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    /**
     * ClassName: OrderService
     * Package: com.mcode.orderclient.service
     * Description:
     *
     * @Author: robin
     * @Create: 2023/10/22 - 1:40 PM
     * @Version: v1.0
     */
    @FeignClient(value = "order-service",path = "order")
    public interface OrderService {
        @GetMapping("/{id}")
        Order getOrderById(@PathVariable("id") Integer id);
    }
    

    添加OrderController用来测试

    package com.mcode.orderclient.controller;
    
    import com.mcode.orderclient.bean.Order;
    import com.mcode.orderclient.service.OrderService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * ClassName: OrderController
     * Package: com.mcode.orderclient.controller
     * Description:
     *
     * @Author: robin
     * @Create: 2023/10/22 - 1:38 PM
     * @Version: v1.0
     */
    @RestController
    @RequestMapping("/order")
    public class OrderController {
        @Autowired
        private OrderService orderService;
    
        @GetMapping("/{id}")
        public Order getOrderById(@PathVariable("id") Integer id){
            return orderService.getOrderById(id);
        }
    }
    

    三、效果

    Nacos

    image

    测试

    image

    四、配置说明

    1、超时配置

    全局超时配置

    spring:
      cloud:
        openfeign:
          client:
            config:
              default:  # 全局设置
                # 连接超时:client连接上service的时间阈值,起决定作用的是网络状况
                connect-timeout: 1
                # 读超时:client发出请求到接收到service的响应这段时间阈值,起决定作用的是service的业务逻辑
                read-timeout: 1
    

    局部超时配置

    在全局设置的基础之上,若想单独对某些微服务单独设置超时时间,只需要将前面配置中的 default 修改为微服务名称即可。局部设置的优先级要高于全局设置的。

    spring:
      cloud:
        openfeign:
          client:
            config:
              default:  # 全局设置
                # 连接超时:client连接上service的时间阈值,起决定作用的是网络状况
                connect-timeout: 1
                # 读超时:client发出请求到接收到service的响应这段时间阈值,起决定作用的是service的业务逻辑
                read-timeout: 1
              order-service: # 局部配置
                connect-timeout: 1
                read-timeout: 2            
    

    2、Gzip压缩设置

    OpenFeign 可对请求与响应进行压缩设置

    spring:
      cloud:
        openfeign:
          client:
            config:
              default:
                connect-timeout: 1
                read-timeout: 1
              order-service:
                connect-timeout: 1
                read-timeout: 2
          compression:
            request:
              enabled: true
              min-request-size: 2048
              mime-types: ["text/xml", "application/xml", "application/json"]
            response:
              enabled: true
    

    默认值

    image

    3、所有配置

    https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/appendix.html

    五、负载均衡

    OpenFeign 的负载均衡器 Ribbon 默认采用的是轮询算法

    更换负载均衡策略

    工程启动三个实例,它们的端口号分别为8081、8082与8083

    image

    image

    image

    image

    注意:关闭之前的超时和order-service模块添加端口查看

    package com.mcode.orderclient.config;
    
    import org.springframework.cloud.client.ServiceInstance;
    import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
    import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
    import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
    import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
    import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.env.Environment;
    
    /**
     * ClassName: OpenFeignConfig
     * Package: com.mcode.orderclient.config
     * Description:
     *
     * @Author: robin
     * @Create: 2023/10/22 - 3:48 PM
     * @Version: v1.0
     */
    @Configuration
    @LoadBalancerClients(defaultConfiguration = OpenFeignConfig.class)
    public class OpenFeignConfig {
       @Bean
        public ReactorLoadBalancer loadBalancer(Environment e, LoadBalancerClientFactory factory){
           // 获取负载均衡客户端名称,即提供者服务名称
           String name = e.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
           // 从所有service实例中指定名称的实例列表中随机选择一个实例
           // 参数1:获取指定名称的所有service实例列表
           // 参数2:指定要获取的service服务名称
           return  new RandomLoadBalancer(factory.getLazyProvider(name, ServiceInstanceListSupplier.class),name);
       }
    }
    

    image

    五、对比Feign

    Feign 的远程调用底层实现技术默认采用的是 JDK 的 URLConnection,同时还支持HttpClient 与 OkHttp。由于 JDK 的 URLConnection 不支持连接池,通信效率很低,所以生产中是不会使用该默认实现的。

    Spring Cloud OpenFeign 中直接将默认实现变为了 HttpClient,同时也支持OkHttp。用户可根据业务需求选择要使用的远程调用底层实现技术。

    spring.cloud.openfeign.httpclient 下有大量 HttpClient 的相关属性设置。其中可以发现spring.cloud.openfeign.httpclient.enabled 默认为 true。 在 spring.cloud.openfeign.okhttp.enabled 默认值为 false,表明默认没有启动 OkHttp。

    从Spring Cloud OpenFeign 4开始,不再支持Feign Apache HttpClient 4。我们建议使用Apache HttpClient 5。

          httpclient:
            hc5:
              enabled: true
    
  • 相关阅读:
    Docker服务systemd配置文件详解
    peer_connection_interface参数
    mini-imagenet数据集下载-阿里云网盘不限速下载
    lvs+keepalived
    excel计算时间差
    短视频账号矩阵系统源码saas===独立部署
    pdfH5实现pdf预览功能
    数据化运营05 关注用户留存就够了吗?值得你关注的另外 3 种留存
    后端面试话术集锦第 十五 篇:java线程面试话术
    大家都能看得懂的源码之ahooks useInfiniteScroll
  • 原文地址:https://www.cnblogs.com/vic-tory/p/17780620.html