SpringCloud OpenFeign服务调用客户端介绍及配置使用

一、OpenFeign介绍

OpenFeign是Netfix开发的一款声明式,模板化的Http服务调用客户端。使用在服务调用者工程端。OpenFeign的负载均衡也为客户端负载均衡。一下简称Feign。

  • Feign可以更加便捷,优雅的调用Http API接口。
  • SpringCloud中,使用Feign非常简单,创建一个接口,并在接口上添加一些注解,即调用类代码开发完成。
  • Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解
  • SpringCloud 对Feign进行了增强,使Feign支持了SpringMVC注解,并整合了Ribbon和Eureka从而让Feign使用更加方便

Feign 与 OpenFeign的区别:Feign是Springcloud组件中的一个轻量级Restful的HTTP服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务;OpenFeign是springcloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

二、基本配置使用

1,添加openfen依赖:

<!-- springCloud 整合的openFeign -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2,启动类添加激活OpenFeign注解@EnableFeignClients

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

3,编写http远程调用接口类

@FeignClient(name="CLOUD-PAYMENT-SERVICE")
public interface ProductFeignClient {

    @RequestMapping(value="/payment/get/{id}",method = RequestMethod.GET)
    CommonResult getPayment(@PathVariable("id") Long id);

    @GetMapping("/payment/get/timeout")
    CommonResult getPaymentTimeout();
}

注意接口类需要添加@FeignClient(name="CLOUD-PAYMENT-SERVICE") 注解。注解中name值为服务提供者服务名称。 接口中方法需要添加SpringMVC注解来声明调用的远程方法路径。方法参数要与远程接口提供方参数一致。

4,在Controller中注入并使用调用

@RestController
public class OrderController {

    @Autowired
    private ProductFeignClient productFeignClient;

    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable("id") Long id){
        return productFeignClient.getPayment(id);
    }

    @GetMapping("/consumer/payment/get/timeout")
    public CommonResult getPaymentTimeout(){
        return productFeignClient.getPaymentTimeout();
    }
}

在Controller中使用比较简单,注解注入接口类,然后使用接口类方法直接调用即可。和我们之前单机版的Controller调用Service结构比较一致。

测试验证:我们启动Eureka注册中心,并分别启动服务提供者工程2个,和当前feign工程。访问feign工程的controller中方法地址,相关展示信息如下:

SpringCloud OpenFeign服务调用客户端介绍及配置使用

SpringCloud OpenFeign服务调用客户端介绍及配置使用

三、负载均衡配置

由于OpenFeign对ribbon的支持所以,OpenFeign的负载均衡也是客户端负载均衡,配置方式和ribbon的也一样。最*的为服务名称。默认的为轮询策略,如下配置的为随机策略。

CLOUD-PAYMENT-SERVICE:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

负载均衡测试:我们启动两个生产者工程端口分别为8002 和 8003,并将调用执行的节点端口进行返回。首先不配置负载均衡相关配置进行测试

SpringCloud OpenFeign服务调用客户端介绍及配置使用

如下为配置了随机请求后的访问效果。

SpringCloud OpenFeign服务调用客户端介绍及配置使用

 

四、超时及日志级别配置

在开发或这运行时,如果需要看到Feign的请求过程可以通过Feign的日志进行查看。默认情况下Feign日志没有开启。如果需要开启,则需要在yml中添加如下feign.client.config中设置即可。

其中loggerLevel中枚举包含:

  • NONE:性能最佳,不包含任何日志,默认值;
  • BASIC:仅记录请求方法、URL、相应状态码以及执行时间;
  • HEADERS:在BASIC的基础上记录请求和相应的Header信息;
  • FULL:记录请求和相应的header、body、和元数据。

超时时间可以在connectTimeout、和readTimeout中配置。

feign:
  client:
    config:
      CLOUD-PAYMENT-SERVICE:
        loggerLevel: FULL
        connectTimeout: 5000
        readTimeout: 5000
logging:
  level:
    com.xiaohui.springcloud.service.ProductFeignClient: debug

配置为FULL时的打印信息:

2020-11-27 20:48:38.893 DEBUG 5832 --- [nio-9001-exec-8] c.x.s.service.ProductFeignClient         : [ProductFeignClient#getPayment] ---> GET http://CLOUD-PAYMENT-SERVICE/payment/get/6203063 HTTP/1.1
2020-11-27 20:48:38.893 DEBUG 5832 --- [nio-9001-exec-8] c.x.s.service.ProductFeignClient         : [ProductFeignClient#getPayment] ---> END HTTP (0-byte body)
2020-11-27 20:48:38.914 DEBUG 5832 --- [nio-9001-exec-8] c.x.s.service.ProductFeignClient         : [ProductFeignClient#getPayment] <--- HTTP/1.1 200 (20ms)
2020-11-27 20:48:38.914 DEBUG 5832 --- [nio-9001-exec-8] c.x.s.service.ProductFeignClient         : [ProductFeignClient#getPayment] connection: keep-alive
2020-11-27 20:48:38.914 DEBUG 5832 --- [nio-9001-exec-8] c.x.s.service.ProductFeignClient         : [ProductFeignClient#getPayment] content-type: application/json
2020-11-27 20:48:38.914 DEBUG 5832 --- [nio-9001-exec-8] c.x.s.service.ProductFeignClient         : [ProductFeignClient#getPayment] date: Fri, 27 Nov 2020 12:48:38 GMT
2020-11-27 20:48:38.914 DEBUG 5832 --- [nio-9001-exec-8] c.x.s.service.ProductFeignClient         : [ProductFeignClient#getPayment] keep-alive: timeout=60
2020-11-27 20:48:38.914 DEBUG 5832 --- [nio-9001-exec-8] c.x.s.service.ProductFeignClient         : [ProductFeignClient#getPayment] transfer-encoding: chunked
2020-11-27 20:48:38.915 DEBUG 5832 --- [nio-9001-exec-8] c.x.s.service.ProductFeignClient         : [ProductFeignClient#getPayment] 
2020-11-27 20:48:38.915 DEBUG 5832 --- [nio-9001-exec-8] c.x.s.service.ProductFeignClient         : [ProductFeignClient#getPayment] {"code":0,"message":"查询成功 server node:172.18.58.92:8002","data":{"id":6203063,"serial":"Hello SpringCloud"}}
2020-11-27 20:48:38.915 DEBUG 5832 --- [nio-9001-exec-8] c.x.s.service.ProductFeignClient         : [ProductFeignClient#getPayment] <--- END HTTP (116-byte body)

五、项目完整文件及目录

SpringCloud OpenFeign服务调用客户端介绍及配置使用SpringCloud OpenFeign服务调用客户端介绍及配置使用

父工程pom文件:

<?xml version="1.0" encoding="UTF-8"?>

<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.0</modelVersion>

  <groupId>com.xiaohui.springCloud</groupId>
  <artifactId>SpringCloud</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.2.RELEASE</version>
  </parent>

  <modules>
    <module>product_service</module>
    <module>cloud-api-common</module>
    <module>eureka_server</module>
    <module>openfeign_order_service</module>
  </modules>

  <!-- 统一jar包管理 -->
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <junit.version>4.12</junit.version>
    <log4j.version>1.2.17</log4j.version>
    <lombok.version>1.16.18</lombok.version>
    <mysql.version>5.1.47</mysql.version>
    <druid.version>1.1.16</druid.version>
    <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
  </properties>

  <!-- 子模块继承之后,提供作用:锁定版本+子模块不用写groupId和version -->
  <dependencyManagement>
    <dependencies>
      <!-- spring boot 2.2.2 -->
     <!-- <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-dependencies</artifactId>
          <version>2.2.2.RELEASE</version>
          <type>pom</type>
          <scope>import</scope>
      </dependency>-->
      <!-- spring cloud Hoxton.SR1 -->
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Hoxton.SR1</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>

      <!-- springcloud alibaba -->
      <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>2.1.0.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>

      <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>${druid.version}</version>
      </dependency>
      <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>${mybatis.spring.boot.version}</version>
      </dependency>

      <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.version}</version>
      </dependency>

      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
      </dependency>

      <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>${lombok.version}</version>
        <optional>true</optional>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <build>
    <plugins>
      <!-- maven 插件 -->
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <fork>true</fork>
          <addResources>true</addResources>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
1,openfeign_order_service 子模块 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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">
    <parent>
        <artifactId>SpringCloud</artifactId>
        <groupId>com.xiaohui.springCloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>openfeign_order_service</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.xiaohui.springCloud</groupId>
            <artifactId>cloud-api-common</artifactId>
            <version>${project.version}</version>
        </dependency>

        <!-- springCloud 整合的openFeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <!-- Eureka 客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>

        <!-- web依赖开始 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!-- web依赖结束 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

2,配置文件 application.yml:

server:
  port: 9001

spring:
  application:
    name: openfeign-order-service

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka1.com:9000/eureka/
  instance:
    prefer-ip-address: true #使用ip进行注册
    instance-id: ${spring.cloud.client.ip-address}:${server.port} #向注册中心注册服务ID
    lease-renewal-interval-in-seconds: 5 #发送心跳间隔时间 秒
    lease-expiration-duration-in-seconds: 10 # 服务续约时间 10秒内没有发送心跳(宕机)

CLOUD-PAYMENT-SERVICE:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

#Feign 日志输出配置
feign:
  client:
    config:
      CLOUD-PAYMENT-SERVICE:
        loggerLevel: FULL
        connectTimeout: 5000
        readTimeout: 5000
logging:
  level:
    com.xiaohui.springcloud.service.ProductFeignClient: debug

3,主启动类:

package com.xiaohui.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

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

  4,feign 接口类

package com.xiaohui.springcloud.service;

import com.xiaohui.springcloud.entities.CommonResult;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@FeignClient(name="CLOUD-PAYMENT-SERVICE")
public interface ProductFeignClient {

    @RequestMapping(value="/payment/get/{id}",method = RequestMethod.GET)
    CommonResult getPayment(@PathVariable("id") Long id);

    @GetMapping("/payment/get/timeout")
    CommonResult getPaymentTimeout();
}

5,业务代码 controller

package com.xiaohui.springcloud.controller;

import com.xiaohui.springcloud.entities.CommonResult;
import com.xiaohui.springcloud.entities.Payment;
import com.xiaohui.springcloud.service.ProductFeignClient;
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.RestController;

@RestController
public class OrderController {

    @Autowired
    private ProductFeignClient productFeignClient;

    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable("id") Long id){
        return productFeignClient.getPayment(id);
    }

    @GetMapping("/consumer/payment/get/timeout")
    public CommonResult getPaymentTimeout(){
        return productFeignClient.getPaymentTimeout();
    }
}

 

上一篇:Spring Cloud Hoxton.SR9版本(五)OpenFeign


下一篇:SpringCloud Hoxton版 + SpringCloud alibaba学习笔记(4)-- OpenFeign服务接口调用