本文最后更新于:2025年2月20日 晚上
远程调用之OpenFeign
在单体项目中,正常写的接口都是供前端调用获取数据的(例如:ajax
、axios
和fetch
)。但是在微服务下的分布式架构中,不同的业务功能模块由不同人员负责并开发,因为分的比较细,所以就少不了服务之间的沟通。通常java
来进行远程调用的方法包括:RestTemplate
、HttpURLConnection
、HttpClient
、OkHttp
等。
而OpenFeign
就是简化微服务之间接口调用的远程调用工具之一。
前提已启动Nacos
注册中心!
一、Maven依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
|
二、启用OpenFeign
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com.demo;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients @SpringBootApplication public class Main { public static void main(String[] args) { SpringApplication.run(Main.class, args); } }
|
三、编写OpenFeign
客户端
这一步类似Mapper文件,只不过数据通过远程调用从其他模块获取。而不是单体中由xml
文件写SQL
语句直接沟通数据库。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.demo.feign;
import com.demo.feign.fallback.Rest02FallBack; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Repository; import org.springframework.web.bind.annotation.GetMapping;
@Repository @FeignClient(value = "test02",fallback = Rest02FallBack.class)
public interface Rest02 {
@GetMapping("index") String test002(); }
|
四、【可选】OpenFeign
日志配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.demo.config;
import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Configuration public class DefaultFeignConfig {
@Bean public Logger.Level feignLogLevel(){ return Logger.Level.FULL; } }
|
五、【可选】启用日志配置
1、局部生效(客户端中指定配置)
1
| @FeignClient(value = "item-service", configuration = DefaultFeignConfig.class)
|
2、全局生效(配置类中指定默认配置)
1
| @EnableFeignClients(defaultConfiguration = DefaultFeignConfig.class)
|
3、yaml
开启OpenFeign
客户端的日志
OpenFeign
只会在FeignClient
所在包的日志级别为DEBUG时,才会输出日志。而且其日志级别有4级:
- NONE:不记录任何日志信息,这是默认值。
- BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
- HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
- FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。
Feign默认的日志级别就是NONE,所以默认我们看不到请求日志。
1 2 3 4 5
| logging: level: com.demo.feign: debug
|
六、请求超时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| feign: httpclient: enabled: false okhttp: enabled: true client: config: default: connectTimeout: 2000 readTimeout: 3000 loggerLevel: full test02: connectTimeout: 5000 readTimeout: 5000 loggerLevel: full
|
七、超时重试
超时重试机制:超时时间(例如5秒)+ 重试间隔(100毫秒)x 1.5
每次重试的间隔都会比上次长,例如是1.5倍
最大到重试间隔的时间超过最大时间或者重试次数达到最大次数则停止重试。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| package com.demo.config;
import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Configuration public class DefaultFeignConfig {
@Bean public Logger.Level feignLogLevel(){ return Logger.Level.FULL; } @Bean Retryer retryer(){ return new Retryer.Default(100L, TimeUnit.SECONDS.toMillis(1L), 5); } }
|
八、请求拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.demo.interceptor;
import feign.RequestInterceptor; import feign.RequestTemplate; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component;
import java.util.UUID;
@Component @Slf4j public class OpenFeignRequestInterceptor implements RequestInterceptor { @Override public void apply(RequestTemplate requestTemplate) { requestTemplate.header("X-Token",UUID.randomUUID().toString()); } }
|
九、FallBack
兜底返回
远程调用超时或错误时返回的错误信息或兜底数据。
兜底数据:默认数据、缓存数据、假数据… 主要是为了让业务能正常运行。
注意:需搭配Sentinel
服务保护框架,否则不会走兜底的。
客户端:需要fallback
指定兜底实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.demo.feign;
import com.demo.feign.fallback.Rest02FallBack; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Repository; import org.springframework.web.bind.annotation.GetMapping;
@Repository @FeignClient(value = "test02",fallback = Rest02FallBack.class)
public interface Rest02 {
@GetMapping("index") String test002(); }
|
兜底类:实现客户端接口然后在实现方法中增加兜底数据逻辑即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.demo.feign.fallback;
import org.springframework.stereotype.Component;
@Component public class Rest02FallBack implements com.demo.feign.Rest02 { @Override public String test002() { return "Default Data"; } }
|
添加Sentinel
依赖
1 2 3 4 5
| <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
|
配置文件中开启sentinel
1 2 3
| feign: sentinel: enabled: true
|
这样把调用的服务停止,然后去调用就会获得兜底数据了。