8. OpenFeign
8.1 介绍
作为Spring Cloud的子项目之一,Spring Cloud OpenFeign以将OpenFeign
集成到Spring Boot应用中的方式,为微服务架构下服务之间的调用提供了解决方案。首先,利用了OpenFeign的声明式方式定义Web服务客户端;其次还更进一步,通过集成Ribbon
或Eureka
实现负载均衡的HTTP客户端。
在Spring Cloud OpenFeign中,除了OpenFeign自身提供的标注(annotation)之外,还可以使用JAX-RS标注,或者Spring MVC标注。下面还是以OpenFeign标注为例介绍用法。
OpenFeign的标注@FeignClient和@EnableFeignClients
OpenFeign提供了两个重要标注@FeignClient和@EnableFeignClients。
@FeignClient标注用于声明Feign客户端可访问的Web服务。
@EnableFeignClients标注用于修饰Spring Boot应用的入口类,以通知Spring Boot启动应用时,扫描应用中声明的Feign客户端可访问的Web服务。
@EnableFeignClients标注的参数
- value, basePackages (默认{})
- basePackageClasses (默认{})
- defaultConfiguration (默认{})
- clients (默认{})
@FeignClient标注的参数
- name, value (默认""),两者等价
- qualifier (默认"")
- url (默认"")
- decode404 (默认false)
- configuration (默认FeignClientsConfiguration.class)
- fallback (默认void.class)
- fallbackFactory (默认void.class)
- path (默认"")
- primary (默认true)
@FeignClient标注的configuration参数
@FeignClient标注的configuration参数,默认是通过FeignClientsConfiguration类定义的,可以配置Client,Contract,Encoder/Decoder等。
FeignClientsConfiguration类中的配置方法及默认值如下:
- feignContract: SpringMvcContract
- feignDecoder: ResponseEntityDecoder
- feignEncoder: SpringEncoder
- feignLogger: Slf4jLogger
- feignBuilder: Feign.Builder
- feignClient: LoadBalancerFeignClient(开启Ribbon时)或默认的HttpURLConnection
定制@FeignClient标注的configuration类
@FeignClient标注的默认配置类为FeignClientsConfiguration,我们可以定义自己的配置类如下:
@Configuration
public class MyConfiguration {
@Bean
public Contract feignContract(...) {....}
@Bean
public Encoder feignEncoder() {...}
@Bean
public Decoder feignDecoder() {...}
...
}
然后在使用@FeignClient标注时,给出参数如下:
@FeignClient(name = "myServiceName", configuration = MyConfiguration.class, ...)
public interface MyService {
@RequestMapping("/")
public String getName();
...
}
定制@FeignClient标注的configuration类还可以有另一个方法,直接配置application.yaml文件即可,示例如下:
feign:
client:
config:
feignName: myServiceName
connectTimeout: 5000
readTimeout: 5000
loggerLevel: full
encoder: com.example.MyEncoder
decoder: com.example.MyDecoder
contract: com.example.MyContract
8.2 feign 和OpenFeign的区别
Feign
Feign是Springcloud组件中的一个轻量级Restful的HTTP服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务
OpenFeign
OpenFeign是springcloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
8.3 OpenFeign的使用
8.3.1创建modules(子项目)
类型 | 值 |
---|---|
groupId | org.jshand (与父项目保持一致即可) |
artifactId | 10-cloud-customer-openfeign-80 (也可随意) |
8.3.2 修改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-202101</artifactId>
<groupId>org.jshand</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>10-cloud-customer-openfeign-80</artifactId>
<dependencies>
<!--openfeign 客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--Eureka Client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
8.3.3 application.yaml配置文件
server:
port: 80
spring:
application:
name: cloud-member-center-service
eureka:
client:
serviceUrl:
defaultZone: http://server8760.com:8760/eureka
instance:
hostname: 127.0.0.1
instance-id: order-80
prefer-ip-address: true
8.3.4 主启动类
在主启动类上添加@EnableFeignClients注解,激活使用@FeignClient注解标注的Feign客户端。
package org.jshand.cloud;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* 使用OpenFeign作为客户端
*/
@SpringBootApplication
@Slf4j
@EnableFeignClients
public class MemberCenterOpenFeignApp {
public static void main(String[] args) {
SpringApplication.run(MemberCenterOpenFeignApp.class, args);
}
}
8.3.5 定义Feign接口
定义调用远程服务的接口,并声明 @FeignClient注解,其中name或者value为微服务名称(即注册中心的服务名)
package org.jshand.cloud.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 定义OpenFeign客户端接口
*/
@Component
@FeignClient(name="PAYMENT")
public interface PaymentService {
@RequestMapping(value = "/echo/{string}")
public String echo(@PathVariable String string);
}
8.3.6 定义Controller调用Feign接口
package org.jshand.cloud.controller;
import lombok.extern.slf4j.Slf4j;
import org.jshand.cloud.service.PaymentService;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@Slf4j
public class MemberCenterController {
@Resource
PaymentService paymentService;
/**
* http://127.0.0.1:80/openfeign/consumer/echo/abc
* @param string
* @return
*/
@RequestMapping(value = "/openfeign/consumer/echo/{string}")
public String echo(@PathVariable String string){
return paymentService.echo(string);
}
}
8.3.7 浏览器测试
使用地址 http://127.0.0.1:80/openfeign/consumer/echo/abc
进行测试,能够正常访问微服务,并提供负载均衡的特性。截图略
8.4 OpenFeign超时控制
默认OpenFeign客户端等待时间为1秒钟,如果服务端超过1秒钟没有返回,则客户端直接抛出Timeout,为了避免这样的情况,有时候我们需要处理Feign客户端的超时控制。
为了模拟上述问题,在服务端控制器方法中添加如下代码(如果是集群,需要每个应用都加),让服务端处理时间延长
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
添加完上述代码后,浏览器单独访问服务端成功没有问题,但是使用OpenFeign客户端调用时报如下错误
为了解决上述问题,此时需要配置客户端。在客户端配置Feign客户端超时时间。其他OpenFeign配置参考链接
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
或者直接设置Ribbon的超时时间, 其他配置请参考连接
ribbon:
ConnectTimeout: 8000
ReadTimeout: 8000
8.5 日志打印功能
OpenFeign提供了打印日志功能,提供了如下级别。开发过程中可以通过配置来调整日志级别,从而了解OpenFeign在调用http请求的过程中的细节。
NONE: 默认的,不显示任何日志
BASIC: 仅记录请求方法、URL、响应状态码以及执行时间
HEADERS:除了BASIC 中自定义的信息外,还有请求和响应的信息头
FULL: 除了HEADERS中定义的信息外, 还有请求和响应的正文以及元数据。
以Full类型为例,需要做如下功能:
8.5.1 定义配置类
定义配置类,用于提供日志类型
package org.jshand.cloud.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfig {
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
8.5.2 配置日志级别
在application.yml中配置FeignClient客户端类的日志级别
logging:
level:
org.jshand.cloud.service.PaymentService: debug
测试后控制台打印如下日志
