feign整合了ribbon和hystrix,除了提供这两者的强大功能之外, 它还提供了一种声明式的web服务客户端定义方式
快速入门
依赖
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
配置
server:
port: 30004
eureka:
client:
# 指定注册中心地址
service-url:
defaultZone: http://localhost:30000/eureka/
spring:
application:
name: FEIGN-CONSUMER
启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class FeignConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(FeignConsumerApplication.class, args);
}
}
接口, 服务名不区分大小写
@FeignClient("HELLO-SERVICE")
public interface HelloService {
@GetMapping("/hello")
String test();
}
使用测试
@RestController
public class FeignController {
@Autowired
private HelloService helloService;
@GetMapping("/test")
public String test() {
for (int i = 0; i < 10; i++) {
helloService.test();
}
return helloService.test();
}
}
继承特性
简言之,
- 抽出一个api项目, 将接口和接口用到的实体定义在api项目中;
- 服务提供方的controller实现此接口,并提供具体的实现;
- 服务消费方(feign调用方)构造一个“具体的service”继承此接口,在其他代码中注入“具体的service”, 并使用
好处: 将接口的定义从controller剥离, 轻易实现对接口定义的共享, 实现在构建期的接口绑定,从而有效减少服务客户端的绑定配置。
缺点: 接口变动对项目构建产生影响,可能服务提供方修改了一个接口定义,那么直接会导致客户端工程的构建失败
相关配置
ribbon配置
feign的负载均衡是通过ribbon来实现的
- 全局配置
ribbon.
- 指定服务配置, 针对特定的服务配置ribbon参数
此处的client是在@FeignClient()中定义的客户端名称
- 重试机制
指ribbon的重试,需要在配置文件中开启,注意hystrix的超时时间要大于ribbon的超时时间
hystrix配置
默认情况下, feign会将所有的Feign客户端的方法封装进Hystrix命令中进行服务保护
- 全局配置
- 禁用hystrix
全局关闭
feign:
hystrix:
enabled: false
指定某一个服务关闭
@Configuration
public class DisableHystrixConfig {
@Bean
@Scope("prototype")
public Feign.Builder feignBuilder() {
return Feign.builder();
}
}
@FeignClient(value = "HELLO-SERVICE",configuration = DisableHystrixConfig.class)
public interface HelloService {
@GetMapping("/hello")
String test();
}
- 指定命令配置
对指定的接口名称进行配置,用的太少, 略
- 服务降级配置
配置服务降级类
/**
* 服务降级类
* @author xinzhang
* @date 2020/9/21 16:21
*/
@Service
public class HelloFallbackServiceImpl implements HelloService {
@Override
public String test() {
return "请求失败!";
}
}
/**
* @author xinzhang
* @date 2020/9/21 14:58
*/
@FeignClient(value = "HELLO-SERVICE",fallback = HelloFallbackServiceImpl.class)
public interface HelloService {
@GetMapping("/hello")
String test();
}
- 请求压缩
- 日志记录
feign在构建@FeignClient修饰的服务客户端时,会为每一个客户端构建一个feign.logger实例,使用方法
配置文件中开启日志记录
logging:
level:
top:
xinzhang0618:
feign:
service:
HelloService: DEBUG
日志全局配置,feign默认是NONE
@Configuration
public class FeignLoggerConfig {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
客户端引用配置
@FeignClient(value = "HELLO-SERVICE", configuration = FeignLoggerConfig.class, fallback =
HelloFallbackServiceImpl.class)
public interface HelloService {
@GetMapping("/hello")
String test();
}
测试
2020-09-21 16:32:00.957 DEBUG 10680 --- [io-30004-exec-2] t.x.feign.service.HelloService : [HelloService#test] hello! search-demo!
2020-09-21 16:32:00.957 DEBUG 10680 --- [io-30004-exec-2] t.x.feign.service.HelloService : [HelloService#test] <--- END HTTP (19-byte body)
2020-09-21 16:32:00.958 DEBUG 10680 --- [io-30004-exec-2] t.x.feign.service.HelloService : [HelloService#test] ---> GET http://HELLO-SERVICE/hello HTTP/1.1
2020-09-21 16:32:00.958 DEBUG 10680 --- [io-30004-exec-2] t.x.feign.service.HelloService : [HelloService#test] ---> END HTTP (0-byte body)
2020-09-21 16:32:00.960 DEBUG 10680 --- [io-30004-exec-2] t.x.feign.service.HelloService : [HelloService#test] <--- HTTP/1.1 200 (2ms)
2020-09-21 16:32:00.960 DEBUG 10680 --- [io-30004-exec-2] t.x.feign.service.HelloService : [HelloService#test] connection: keep-alive
2020-09-21 16:32:00.960 DEBUG 10680 --- [io-30004-exec-2] t.x.feign.service.HelloService : [HelloService#test] content-length: 19
2020-09-21 16:32:00.960 DEBUG 10680 --- [io-30004-exec-2] t.x.feign.service.HelloService : [HelloService#test] content-type: text/plain;charset=UTF-8
2020-09-21 16:32:00.960 DEBUG 10680 --- [io-30004-exec-2] t.x.feign.service.HelloService : [HelloService#test] date: Mon, 21 Sep 2020 08:32:00 GMT
2020-09-21 16:32:00.960 DEBUG 10680 --- [io-30004-exec-2] t.x.feign.service.HelloService : [HelloService#test] keep-alive: timeout=60