概述
Feign 封装了Http 调用流程,更适合面向接口化的变成习惯。
- Feign 宗旨:使编写 Java Http 客户端变得更容易。
-
通过 Feign 只需要定义服务绑定接口且以声明式的方法
,优雅而简单的显示了服务调用。
- Feign 集成了 Ribbon,通过轮训实现了客户端的负载均衡。
Feign 是如何设计?
快速上手
项目架构如下图:
- Client:从 Nacos Server 中获取需要调用的微服务的信息(IP 和 Port)
- Server:会将自己的信息注册进 Nacos Server
- Client:通过 OpenFeign 远程调用 Server 服务。
client 项目
主要 mvn 依赖
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--nacos-discovery-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
yaml 配置信息
server:
port: 80
spring:
application:
name: cloud-client-feign80
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
主启动类:注意通过注解需要 @EnableFeignClients 启动 Feign
@SpringBootApplication
@EnableFeignClients
public class FeignMain80 {
public static void main(String[] args) {
SpringApplication.run(FeignMain80.class, args);
}
}
业务类
- @FeignClient 这个注解表示此类使用 FeignClient 进行远程调用。
- @FeignClient 的 value 值是:需要调用的微服务在 Nacos 中注册的名称。
- FeignClient 通过 微服务名称 + GetMapping 的地址,定位到需要调用的是哪个服务。
@Component
@FeignClient(value = "cloudalibaba-sentinel-service")
public interface FeignService {
@GetMapping(value = "/user/{id}")
User getUserById(@PathVariable("id") Long id);
}
Controller
- 后端程序员习惯面向接口编程,通过 OpenFeign 的封装,符合了程序的开发习惯。
@RestController
public class FeignController {
@Resource
private FeignService feignService;
@GetMapping(value = "/feign/user/get/{id}")
public User getPaymentById(@PathVariable("id") Long id) {
return feignService.getUserById(id);
}
}
Server 项目
主要 mvn 依赖
<!--SpringCloud ailibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
yaml 配置信息
server:
port: 8041
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
主启动类
@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8402 {
public static void main(String[] args) {
SpringApplication.run(MainApp8402.class, args);
}
}
Controller
@RestController
public class UserController {
@Value("${server.port}")
private String serverPort;
@GetMapping("/user/{id}")
public User getUserById(@PathVariable("id") int id) {
return User.builder()
.id(id)
.name("dyf" + id)
.age(id + 10)
.serverPort(serverPort)
.build();
}
}
测试
- 启动 Nacos 服务
- 启动 两个 Server 服务
- 启动 Client 服务
如下图:一个Client 和两个 Server 都成功注册进 Nacos 服务。
如下图:通过返回的端口数据,我们可以发现 OpenFeign 具有负载均衡的功能。
超时设置
OpenFeign 默认的超时时间是 1 秒。
开发一个超时接口:
@GetMapping("/user/timeout")
public String timeout() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return serverPort;
}
如下图:有超时错误。
在 Client 项目自定义 OpenFeign 超时
#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
ReadTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间
ConnectTimeout: 5000
请求正常了
配置多个超时时间
yaml 文件中配置多个超时时间
feign:
client:
config:
default:
# 日志级别
loggerLevel: full
# 超时设置
connectTimeout: 1500
readTimeout: 1500
payment-core:
connectTimeout: 5000
readTimeout: 5000
FeignClient 调用时通过 contextId 属性指定使用哪个超时时间。
@FeignClient(name = "payment-service", contextId = "payment-core", path = "/payment")
public interface PaymentFeign {
@PostMapping("/create")
PaymentVo create(@RequestBody @Validated PaymentDto paymentDto);
}
日志配置
日志级别:
- NONE:默认的,不显示任何日志
- BASIC:仅记录请求方法、URL、响应状态码、执行时间。
- HEADERS:处理 BASIC 中定义的信息外,还会打印请求和响应头信息。
- FULL:除了 HEADERS 中定义的信息外,还会打印请求和响应的正文及元数据。
通过配置类:开启 FULL 日志级别。
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
配置哪些类需要打印日志
logging:
level:
# feign日志以什么级别监控哪个接口
com.dyf.springcloud.feign.service.FeignService: debug
打印日志如下图
引入 Sentinel
引入 sentinel mvn 依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
激活 Sentinel 对 Feign 的支持
feign:
sentinel:
enabled: true
新增熔断限量的兜底策略类。
@Component
public class FeignFallbackService implements FeignService {
@Override
public User getUserById(Long id) {
return User.builder()
.id(-1)
.name("限流熔断兜底策略")
.build();
}
@Override
public String timeout() {
return "限流熔断兜底策略";
}
}
在业务类的 @FeignClient 注解上,新增 fallback 的兜底策略。
@Component
@FeignClient(value = "cloudalibaba-sentinel-service", fallback = FeignFallbackService.class)
public interface FeignService {
@GetMapping(value = "/user/{id}")
User getUserById(@PathVariable("id") Long id);
@GetMapping("/user/timeout")
String timeout();
}
主启动类新增 @EnableDiscoveryClient 开启 Sentinel
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class FeignMain80 {
public static void main(String[] args) {
SpringApplication.run(FeignMain80.class, args);
}
}
测试
- 启动 Client 服务
- 关闭 Server 服务,模拟 Server 服务异常。
如下图:已经走了兜底策略。