一、简介
官网:https://spring.io/projects/spring-cloud-openfeign
文档:https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/
配置:https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/appendix.html
OpenFeign是一个显示声明式的WebService客户端。使用OpenFeign能让编写Web Service客户端更加简单。使用时只需定义服务接口,然后在上面添加注解。OpenFeign也支持可拔插式的编码和解码器。spring cloud对feign进行了封装,使其支持MVC注解和HttpMessageConverts。和eureka(服务注册中心)和ribbon组合可以实现负载均衡。在Spring Cloud中使用OpenFeign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问HTTP请求,非常的方便。
OpenFeign 具有负载均衡功能,其可以对指定的微服务采用负载均衡方式进行消费、访问。之前老版本 Spring Cloud 所集成的 OpenFeign 默认采用了 Ribbon 负载均衡器。但由于Netflix 已不再维护 Ribbon,所以从 Spring Cloud 2021.x 开始集成的 OpenFeign 中已彻底丢弃Ribbon,而是采用 Spring Cloud 自行研发的 Spring Cloud Loadbalancer 作为负载均衡器
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-loadbalancerartifactId>
dependency>
注意:负载均衡必须引入loadbalancer
二、使用
环境:
jdk:17
idea:2023.2
spring-boot:3.0.2
1、创建父工程
引入坐标
<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.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>3.0.2version>
<relativePath/>
parent>
<groupId>com.mcodegroupId>
<artifactId>openfeign-demoartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>pompackaging>
<name>openfeign-demoname>
<url>http://maven.apache.orgurl>
<properties>
<java.version>17java.version>
<spring-cloud.version>2022.0.0spring-cloud.version>
<spring-cloud-alibaba.version>2022.0.0.0spring-cloud-alibaba.version>
properties>
<modules>
<module>order-clientmodule>
<module>order-servicemodule>
modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-dependenciesartifactId>
<version>${spring-cloud-alibaba.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
2、创建order-service模块
导入坐标
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>com.mcodegroupId>
<artifactId>openfeign-demoartifactId>
<version>1.0-SNAPSHOTversion>
parent>
<artifactId>order-serviceartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>order-servicename>
<description>order-servicedescription>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
project>
配置application.yml
spring:
application:
name: order-service
cloud:
nacos:
discovery:
username: nacos
password: nacos
server-addr: localhost:8848
server:
port: 8081
配置启动类,启动Nacos注入
package com.mcode.orderservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
添加Order类,用来测试
package com.mcode.orderservice.bean;
import lombok.Data;
/**
* ClassName: Order
* Package: com.mcode.orderservice.bean
* Description:
*
* @Author: robin
* @Create: 2023/10/22 - 1:32 PM
* @Version: v1.0
*/
@Data
public class Order {
private Integer id;
private String orderNo;
private String productName;
}
添加OrderController控制器
package com.mcode.orderservice.controller;
import com.mcode.orderservice.bean.Order;
import org.springframework.web.bind.annotation.*;
/**
* ClassName: OrderController
* Package: com.mcode.orderservice.controller
* Description:
*
* @Author: robin
* @Create: 2023/10/22 - 1:31 PM
* @Version: v1.0
*/
@RestController
@RequestMapping("/order")
public class OrderController {
//方便后面的负载均衡测试
@Value("${server.port}")
public int port;
@GetMapping("/{id}")
public Order getOrderById(@PathVariable("id") Integer id){
Order order = new Order();
order.setOrderNo("20201213");
order.setProductName("商品名称 端口:" + port);
order.setId(1);
return order;
}
}
3、创建order-client模块
导入坐标
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>com.mcodegroupId>
<artifactId>openfeign-demoartifactId>
<version>1.0-SNAPSHOTversion>
parent>
<artifactId>order-clientartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>order-clientname>
<description>order-clientdescription>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>
<dependencies>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-loadbalancerartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
project>
配置application.yml
spring:
application:
name: order-client
cloud:
nacos:
discovery:
username: nacos
password: nacos
server-addr: localhost:8848
server:
port: 8080
配置启动类,启动FeignClient和Nacos
package com.mcode.orderclient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class OrderClientApplication {
public static void main(String[] args) {
SpringApplication.run(OrderClientApplication.class, args);
}
}
添加Order类,用来测试
package com.mcode.orderclient.bean;
import lombok.Data;
/**
* ClassName: Order
* Package: com.mcode.orderclient.bean
* Description:
*
* @Author: robin
* @Create: 2023/10/22 - 1:32 PM
* @Version: v1.0
*/
@Data
public class Order {
private Integer id;
private String orderNo;
private String productName;
}
添加OrderService,用来定义Feign接口
package com.mcode.orderclient.service;
import com.mcode.orderclient.bean.Order;
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.ResponseBody;
/**
* ClassName: OrderService
* Package: com.mcode.orderclient.service
* Description:
*
* @Author: robin
* @Create: 2023/10/22 - 1:40 PM
* @Version: v1.0
*/
@FeignClient(value = "order-service",path = "order")
public interface OrderService {
@GetMapping("/{id}")
Order getOrderById(@PathVariable("id") Integer id);
}
添加OrderController用来测试
package com.mcode.orderclient.controller;
import com.mcode.orderclient.bean.Order;
import com.mcode.orderclient.service.OrderService;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* ClassName: OrderController
* Package: com.mcode.orderclient.controller
* Description:
*
* @Author: robin
* @Create: 2023/10/22 - 1:38 PM
* @Version: v1.0
*/
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("/{id}")
public Order getOrderById(@PathVariable("id") Integer id){
return orderService.getOrderById(id);
}
}
三、效果
Nacos
测试
四、配置说明
1、超时配置
全局超时配置
spring:
cloud:
openfeign:
client:
config:
default: # 全局设置
# 连接超时:client连接上service的时间阈值,起决定作用的是网络状况
connect-timeout: 1
# 读超时:client发出请求到接收到service的响应这段时间阈值,起决定作用的是service的业务逻辑
read-timeout: 1
局部超时配置
在全局设置的基础之上,若想单独对某些微服务单独设置超时时间,只需要将前面配置中的 default 修改为微服务名称即可。局部设置的优先级要高于全局设置的。
spring:
cloud:
openfeign:
client:
config:
default: # 全局设置
# 连接超时:client连接上service的时间阈值,起决定作用的是网络状况
connect-timeout: 1
# 读超时:client发出请求到接收到service的响应这段时间阈值,起决定作用的是service的业务逻辑
read-timeout: 1
order-service: # 局部配置
connect-timeout: 1
read-timeout: 2
2、Gzip压缩设置
OpenFeign 可对请求与响应进行压缩设置
spring:
cloud:
openfeign:
client:
config:
default:
connect-timeout: 1
read-timeout: 1
order-service:
connect-timeout: 1
read-timeout: 2
compression:
request:
enabled: true
min-request-size: 2048
mime-types: ["text/xml", "application/xml", "application/json"]
response:
enabled: true
默认值
3、所有配置
https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/appendix.html
五、负载均衡
OpenFeign 的负载均衡器 Ribbon 默认采用的是轮询算法
更换负载均衡策略
工程启动三个实例,它们的端口号分别为8081、8082与8083
注意:关闭之前的超时和order-service模块添加端口查看
package com.mcode.orderclient.config;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* ClassName: OpenFeignConfig
* Package: com.mcode.orderclient.config
* Description:
*
* @Author: robin
* @Create: 2023/10/22 - 3:48 PM
* @Version: v1.0
*/
@Configuration
@LoadBalancerClients(defaultConfiguration = OpenFeignConfig.class)
public class OpenFeignConfig {
@Bean
public ReactorLoadBalancer loadBalancer(Environment e, LoadBalancerClientFactory factory){
// 获取负载均衡客户端名称,即提供者服务名称
String name = e.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
// 从所有service实例中指定名称的实例列表中随机选择一个实例
// 参数1:获取指定名称的所有service实例列表
// 参数2:指定要获取的service服务名称
return new RandomLoadBalancer(factory.getLazyProvider(name, ServiceInstanceListSupplier.class),name);
}
}
五、对比Feign
Feign 的远程调用底层实现技术默认采用的是 JDK 的 URLConnection,同时还支持HttpClient 与 OkHttp。由于 JDK 的 URLConnection 不支持连接池,通信效率很低,所以生产中是不会使用该默认实现的。
Spring Cloud OpenFeign 中直接将默认实现变为了 HttpClient,同时也支持OkHttp。用户可根据业务需求选择要使用的远程调用底层实现技术。
在 spring.cloud.openfeign.httpclient
下有大量 HttpClient 的相关属性设置。其中可以发现spring.cloud.openfeign.httpclient.enabled
默认为 true。 在 spring.cloud.openfeign.okhttp.enabled
默认值为 false,表明默认没有启动 OkHttp。
从Spring Cloud OpenFeign 4开始,不再支持Feign Apache HttpClient 4。我们建议使用Apache HttpClient 5。
httpclient:
hc5:
enabled: true