Spring Cloud OpenFeign:基于Ribbon和Hystrix的声明式服务调用
Feign简介
Feign是声明式的服务调用工具,我们只需创建一个接口并用注解的方式来配置它,就可以实现对某个服务接口的调用,简化了直接使用RestTemplate来调用服务接口的开发量。Feign具备可插拔的注解支持,同时支持Feign注解、JAX-RS注解及SpringMvc注解。当使用Feign时,Spring Cloud集成了Ribbon和Eureka以提供负载均衡的服务调用及基于Hystrix的服务容错保护功能。
创建一个feign-service模块
pom中添加依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>feign-service</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
application.yml
server:
port: 7701
spring:
application:
name: feign-service
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka/
feign:
hystrix:
enabled: true #在Feign中开启Hystrix
logging:
level:
com.dnydys.service.UserService: debug
注解来启用Feign的客户端功能
在启动类上添加@EnableFeignClients来启用Feign的客户端功能
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class FeignServiceApplication {
public static void main(String[] args) {
SpringApplication.run(FeignServiceApplication.class, args);
}
}
添加UserService接口完成对user-service服务的接口绑定
/**
* @author dnydys
* @description
* @updateTime 2022/1/23
*/
@FeignClient(value = "user-service",fallback = UserFallbackService.class)
public interface UserService {
@PostMapping("/user/create")
CommonResult create(@RequestBody User user);
@GetMapping("/user/{id}")
CommonResult<User> getUser(@PathVariable Long id);
@GetMapping("/user/getByUsername")
CommonResult<User> getByUsername(@RequestParam String username);
@PostMapping("/user/update")
CommonResult update(@RequestBody User user);
@PostMapping("/user/delete/{id}")
CommonResult delete(@PathVariable Long id);
}
添加UserFeignController调用UserService实现服务调用
/**
* @author dnydys
* @description
* @updateTime 2022/1/23
*/
@RestController
@RequestMapping("/user")
public class UserFeignController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public CommonResult getUser(@PathVariable Long id) {
return userService.getUser(id);
}
@GetMapping("/getByUsername")
public CommonResult getByUsername(@RequestParam String username) {
return userService.getByUsername(username);
}
@PostMapping("/create")
public CommonResult create(@RequestBody User user) {
return userService.create(user);
}
@PostMapping("/update")
public CommonResult update(@RequestBody User user) {
return userService.update(user);
}
@PostMapping("/delete/{id}")
public CommonResult delete(@PathVariable Long id) {
return userService.delete(id);
}
}
负载均衡功能演示
启动eureka-service,两个user-service(SpringCloud中一套代码启动两个服务(修改端口号即可)),feign-service服务,启动后注册中心显示如下:
多次调用http://localhost:7701/user/1进行测试,可以发现运行在7201和7202的user-service服务交替打印如下信息:
添加服务降级实现类UserFallbackService
注意: 它实现了UserService接口,并且对接口中的每个实现方法进行了服务降级逻辑的实现。
/**
* @author dnydys
* @description
* @updateTime 2022/1/23
*/
@Component
public class UserFallbackService implements UserService {
@Override
public CommonResult create(User user) {
User defaultUser = new User(-1L, "defaultUser", "123456");
return new CommonResult<>(defaultUser);
}
@Override
public CommonResult<User> getUser(Long id) {
User defaultUser = new User(-1L, "defaultUser", "123456");
return new CommonResult<>(defaultUser);
}
@Override
public CommonResult<User> getByUsername(String username) {
User defaultUser = new User(-1L, "defaultUser", "123456");
return new CommonResult<>(defaultUser);
}
@Override
public CommonResult update(User user) {
return new CommonResult("调用失败,服务被降级",500);
}
@Override
public CommonResult delete(Long id) {
return new CommonResult("调用失败,服务被降级",500);
}
}
在yml中添加配置
feign:
hystrix:
enabled: true #在Feign中开启Hystrix
服务降级功能演示
关闭两个user-service服务,重新启动feign-service
调用http://localhost:7701/user/1进行测试,可以发现返回了服务降级信息
日志打印功能
Feign提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解Feign中Http请求的细节。
日志级别
- NONE:默认的,不显示任何日志;
- BASIC:仅记录请求方法、URL、响应状态码及执行时间;
- HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息;
- FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据。
通过配置开启日志
/**
* @author dnydys
* @description
* @updateTime 2022/1/23
*/
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
在yml中添加配置
logging:
level:
com.dnydys.service.UserService: debug
查看日志
调用http://localhost:7701/user/1进行测试,可以看到以下日志。
2022-02-07 22:13:35.592 DEBUG 6572 --- [-user-service-1] com.dnydys.service.UserService : [UserService#getUser] <--- HTTP/1.1 200 (322ms)
2022-02-07 22:13:35.592 DEBUG 6572 --- [-user-service-1] com.dnydys.service.UserService : [UserService#getUser] content-type: application/json;charset=UTF-8
2022-02-07 22:13:35.592 DEBUG 6572 --- [-user-service-1] com.dnydys.service.UserService : [UserService#getUser] date: Mon, 07 Feb 2022 14:13:35 GMT
2022-02-07 22:13:35.592 DEBUG 6572 --- [-user-service-1] com.dnydys.service.UserService : [UserService#getUser] transfer-encoding: chunked
2022-02-07 22:13:35.592 DEBUG 6572 --- [-user-service-1] com.dnydys.service.UserService : [UserService#getUser]
2022-02-07 22:13:35.593 DEBUG 6572 --- [-user-service-1] com.dnydys.service.UserService : [UserService#getUser] {"data":{"id":1,"username":"admin","password":"admin"},"message":"操作成功","code":200}
2022-02-07 22:13:35.594 DEBUG 6572 --- [-user-service-1] com.dnydys.service.UserService : [UserService#getUser] <--- END HTTP (91-byte body)
2022-02-07 22:13:36.437 INFO 6572 --- [erListUpdater-0] c.netflix.config.ChainedDynamicProperty : Flipping property: user-service.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
Feign的常用配置
Feign自己的配置
feign:
hystrix:
enabled: true #在Feign中开启Hystrix
compression:
request:
enabled: false #是否对请求进行GZIP压缩
mime-types: text/xml,application/xml,application/json #指定压缩的请求数据类型
min-request-size: 2048 #超过该大小的请求会被压缩
response:
enabled: false #是否对响应进行GZIP压缩
logging:
level: #修改日志级别
com.dnydys.service.UserService: debug
Feign中的Ribbon配置
在Feign中配置Ribbon可以直接使用Ribbon的配置,具体可以参考Spring Cloud Ribbon:负载均衡的服务调用
Feign中的Hystrix配置
在Feign中配置Hystrix可以直接使用Hystrix的配置,具体可以参考Spring Cloud Hystrix:服务容错保护