前言
OpenFeign 本身不具备负载均衡能力,而是通过集成 Spring Cloud LoadBalancer (Spring Cloud 2020+ 默认)或 Ribbon (旧版本)实现客户端负载均衡。其核心机制是将 feign.Client 替换为具备负载均衡能力的 LoadBalancerFeignClient(或新版对应的实现),在发起 HTTP 请求前,先从注册中心获取服务实例列表,再根据策略选择一个具体实例进行调用。
若不需要修改负载均衡策略,只需要引入loadbalancer依赖即可,spring自动集成,默认负载均衡算法:轮询。若要修改策略,在yaml中修改配置即可。
一、导入依赖
openFeign的接口测试依赖nacos,所以导入了nacos依赖。
XML
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- 配置中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- 服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>annotationProcessor</scope>
</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>
二、创建order/product/model三个工程
model工程存放两个工程都需要的pojo类。
java
@Data
public class Product {
private Long id;
private BigDecimal price;
private String productName;
private Integer num;
}
三、order工程
1、创建FeignClient接口
java
@FeignClient(value = "service-product",fallback = FeignClientFallBack.class)
public interface FeignClientTest {
@GetMapping("/product/feign")
String getStr();
@PostMapping("/product/feignPost")
String feignPost(@RequestBody Student student);
@GetMapping("/product/feignGet")
String feignGet(@RequestParam("name") String name,
@RequestParam("age") Integer age,
@RequestParam("clazz") String clazz);
}
2、创建测试Controller类
java
@RestController
@RequestMapping("test")
public class TestController {
@Autowired
private FeignClientTest feignClientTest;
@GetMapping("nacos")
public String test1(){
String str = feignClientTest.getStr();
return str;
}
@GetMapping("testGet")
public String testPost(@RequestParam("name") String name, @RequestParam("age") Integer age,
@RequestParam("clazz") String clazz){
Student student = new Student();
student.setClazz(clazz);
student.setAge(age);
student.setName(name);
String s = feignClientTest.feignPost(student);
System.out.println("feignPost 远程接口返回结果:"+s);
return s;
}
@PostMapping("testPost")
public String testGet(@RequestBody Student student){
String s = feignClientTest.feignGet(student.name,student.age,student.clazz);
System.out.println("feignGet 远程接口返回结果:"+s);
return s;
}
}
3、启动类配置
java
@EnableFeignClients //开启feign的远程调用功能
@SpringBootApplication
@EnableDiscoveryClient //开启nacos服务注册发现功能
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class,args);
}
}
4、配置文件配置信息
java
server:
port: 8808
spring:
application:
name: service-order
cloud:
openfeign:
client:
config:
service-product: #在service-order工程中,给调用service-product服务接口的请求配置拦截器。order工程中也可能会有调用其他服务的请求。则不会被拦截。
request-interceptors:
- com.gcy.interceptor.XtokenRequestInterceptor
default:
logger-level: full
connect-timeout: 1000 #默认连接超时时间
read-timeout: 2000 #默认读取超时时间
nacos:
server-addr: 127.0.0.1:8848
config:
import-check:
enabled: false
feign:
sentinel:
enabled: true # 开启兜底回调
logging:
level:
com.gcy.feign: debug
四、product工程
1、创建Controller测试类,供order服务调用。
java
@RestController
@RequestMapping("/product")
public class TestController {
@GetMapping("/feign")
public String test1(){
return "product response : ";
}
@PostMapping("feignPost")
public String feignPost(@RequestBody Student student, HttpServletRequest request) throws InterruptedException {
String header = request.getHeader("x-token");
System.out.println("product server`s x-token:["+header+"]");
// Thread.sleep(3000);
System.out.println("远程接口数据:" + student.toString());
return "远程接口返回数据:" + student.toString();
}
@GetMapping("feignGet")
public String feignGet(@RequestParam("name") String name,
@RequestParam("age") Integer age,
@RequestParam("clazz") String clazz,HttpServletRequest request) throws InterruptedException {
String header = request.getHeader("x-token");
System.out.println("product server`s x-token:["+header+"]");
// Thread.sleep(3000);
System.out.println("远程接口数据:" + "name:" + name+"| age:" + age+"| clazz:" + clazz);
return "远程接口返回数据:" + "name:" + name+"| age:" + age+"| clazz:" + clazz;
}
}
五、当远程接口调用失败,配置兜底回调方法。
1、兜底回调方法实现类。
java
@Component
public class FeignClientFallBack implements FeignClientTest {
@Override
public String getStr() {
return "getStr方法调用远程接口异常";
}
@Override
public String feignPost(Student student) {
return "feignPost方法调用远程接口异常";
}
@Override
public String feignGet(String name, Integer age, String clazz) {
return "feignGet方法调用远程接口异常";
}
}
2、openFeign接口配置兜底回调方法的实现类。
java
@FeignClient(value = "service-product",fallback = FeignClientFallBack.class)
public interface FeignClientTest {
//fallback 属性指定兜底回调方法的实现类。
六、openFeign拦截器。
1、service-order工程中创建拦截器实现类
java
/**
* 一旦给类加了@Component 注解,将bean放入ioc容器,
* 拦截器功能就会对所有的openFeign远程调用生效,不管你在yaml中指定调用service-product服务时添加拦截器。
* 还是指定调用service-logistics服务时添加拦截器。
* 所以要想指定调用某个服务,如调用service-product服务的请求添加拦截器。就不要给拦截器类上添加注解,将拦截器bean放入容器。
*/
//@Component
public class XtokenRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header("x-token", UUID.randomUUID().toString());
}
}
2、yaml配置文件中配置拦截器。
在service-order工程中,给调用service-product工程的请求配置拦截器。
XML
spring:
application:
name: service-order
cloud:
openfeign:
client:
config:
service-product:
request-interceptors:
- com.gcy.interceptor.XtokenRequestInterceptor
工程目录结构
