本文最后更新于271 天前,其中的信息可能已经过时,如有错误请发送邮件到qiqin-chang@qq.com
基础配置:
依赖:
<!--openFeign-远程调用-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--loadbalancer 负载均衡-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
启动类添加注解:
@EnableFeignClients //开启Fegin远程调用功能,需在服务的启动类上添加
方式1:声明扫描包:
@EnableFeignClients(basePackages = “com.chang.api.client”)
方式2:声明要用的FeignClient:
@EnableFeignClients(userClient.class)
使用方法:
- 在要使用的微服务中创建client包,在包中书写远程请求代码
远程调用接口:
@FeignClient("user-service") //服务名称 调用外部API:@FeignClient(value = "服务名称-client",url = "服务地址")
public interface UserClient {
@GetMapping("/users") //请求方式+请求路径
List<UserTO> queryUserByIds(@RequestParam("ids") Collection<Long> ids); //返回值类型+请求参数
}
参数说明:
| 参数 | 说明 |
|---|---|
| @FeignClient(“user-service”) | 声明服务名称 |
| @GetMapping | 声明请求方式 |
| @GetMapping(“/users”) | 声明请求路径 |
| @RequestParam(“ids”) Collection<Long> ids | 声明请求参数 |
| List<UserDTO> | 返回值类型 |
有了上述信息,OpenFeign就可以利用动态代理帮我们实现这个方法,并且向http://chang-service/user发送一个GET请求,携带ids为请求参数,并自动将返回值处理为List<UserDTO>
我们只需要在serviceImpl层中直接调用这个方法,即可实现远程调用了
抽取client模块:
可以创建新的api模块用来统一存储client远程请求代码,在有需要的模块中通过依赖注入
依赖:
<?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>CHANG</artifactId>
<groupId>com.chang</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>hm-api</artifactId>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<!--open feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- load balancer-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!-- swagger 注解依赖 -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.6.6</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
连接池配置:
依赖:
<!--OK http 的依赖 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
配置:
feign:
okhttp:
enabled: true # 开启OKHttp功能
日志配置:
配置:
logging:
level:
com.chang.user.feign: debug #选择需要生成日志的项目路径
配置类:
public class UserConfig {
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.FULL;
}
}
OpenFeign只会在FeignClient所在包的日志级别为DEBUG时,才会输出日志。其日志级别有4级,默认的日志级别是NONE。
日志级别:
| 级别 | 说明 |
|---|---|
| NONE | 不记录任何日志信息,这是默认值 |
| BASIC | 仅记录请求的方法,URL以及响应状态码和执行时间 |
| HEADERS | 在BASIC的基础上,额外记录了请求和响应的头信息 |
| FULL | 记录所有请求和响应的明细,包括头信息、请求体、元数据 |
超时配置:
配置:
spring:
profiles:
include: feign #启用feign配置
application-feign.yaml配置:
spring:
cloud:
openfeign:
client:
config:
default:
logger-level: full
connect-timeout: 1000
read-timeout: 2000
product-service:
logger-level: full
connect-timeout: 3000
read-timeout: 5000
# request-interceptors:
# - com.chang.order.interceptor.XTokenRequestInterceptor #对对应路径下的服务开启拦截器
重试机制:
配置类:
@Bean //重试器
Retryer retryer(){
return new Retryer.Default();
}
拦截器:
拦截器:
@Component //注入容器为开启全局拦截 单一配置请看feign配置文件
public class XTokenRequestInterceptor implements RequestInterceptor {
/**
* 请求拦截器
* @param template 请求模版
*/
@Override
public void apply(RequestTemplate template) {
System.out.println("XTokenRequestInterceptor......");
template.header("X-token", UUID.randomUUID().toString());
}
}
Fallback调用兜底:
依赖:
<!--sentinel 服务保护-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
application-feign.yaml配置:
feign:
sentinel:
enabled: true #开启服务保护
远程调用类:
@FeignClient(value = "product-service",fallback = ProductFeignClientFallback.class) //fallbacke指定回调类
public interface ProductFeignClient {
//mvc注解的两套使用逻辑
//1.标注在Controller上,是接受这样的请求
//2.标注在FeignClient上,是发送这样的请求
@GetMapping("/product/{id}")
Product getProduct(@PathVariable("id") Long id);
}
回调类:
@Component
public class ProductFeignClientFallback implements ProductFeignClient {
@Override
public Product getProduct(Long id) {
System.out.println("兜底回调...");
Product product = new Product();
product.setId(id);
product.setPrice(new BigDecimal("0"));
product.setProductName("位置商品");
product.setNum(0);
return product;
}
}
在微服务之间传递用户信息:
- 存在api服务中
配置类:
public class DefaultFeignConfig {
@Bean
public RequestInterceptor userInfoRequestInterceptor(){
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate template) {
// 获取登录用户
Long userId = UserContext.getUser();
if(userId == null) {
// 如果为空则直接跳过
return;
}
// 如果不为空则放入请求头中,传递给下游微服务
template.header("user-info", userId.toString());
}
};
}
@Bean
public UserClientFallbackFactory ClientFallbackFactory(){
return new UserClientFallbackFactory();
}
}