使用 feign 调用远程接口
Feign
可以把HTTP
的请求进行隐藏,伪装成类似SpringMVC
的controller
一样。你不用再自己拼接url
,拼接参数等等操作,—切都交给Feign
去做。
Feign是一种声明式、模板化的HTTP客户端。在Spring Cloud 中使用Feign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问HTTP请求。
接下来介绍一下Feign的特性,具体如下:
- 集成Ribbon的负载均衡功能
- 集成了Hystrix的熔断器功能
- 支持请求压缩
- 大大简化了远程调用的代码,同时功能还增强啦
- Feign以更加优雅的方式编写远程调用代码,并简化重复代码
入门案例
在user-consumer
项目里加入Feign
在pom.xml
引入坐标
<?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>springcloud-parent</artifactId>
<groupId>org.liu</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>user-consumer</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka客户端中间件 -->
<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-netflix-hystrix</artifactId>
</dependency>
<!-- 配置feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
</project>
因为feign只能在接口上,所以新建一个feign包里面的UserClient ,进行访问调用
package com.liu.consumer.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
//@FeignClient(value = "要调用微服务的名字") //标记为feign接口
@FeignClient(value = "user-provider") //标记为feign接口
public interface UserClient {
@GetMapping("/user/find/{id}")
public String userFind(@PathVariable(value = "id") String id);
}
在启动类上开启feign
package com.liu.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient //启动 Eureka 客户端
@EnableCircuitBreaker // 开启熔断器
@EnableFeignClients(basePackages = "com.liu.consumer.feign") // 开启feign并扫描所在的包
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class,args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
新建一个ConsumerFeignController
做调用测试
package com.liu.consumer.controller;
import com.liu.consumer.feign.UserClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/feign")
public class ConsumerFeignController {
@Autowired
private UserClient userClient;
@RequestMapping("/{id}")
public String findUser(@PathVariable(value = "id") String id){
return userClient.userFind(id);
}
}
在浏览器输入http://127.0.0.1:18082/feign/1
,成功
负载均衡
Feign自身已经集成了Ribbon,因此使用Feign的时候,不需要额外引入依赖。
使用负载均衡就需要 每一个应用(user-provider)都要配置
server:
port: 18082
spring:
application:
name: user-consumer
eureka:
client:
register-with-eureka: true # 是否需要把自己添加到注册中心
service-url:
defaultZone: http://127.0.0.1:7001/eureka # EurekaServer的地址
# 修改服务地址轮询策略,默认是轮询,配置之后变随机
user-provider:
ribbon:
#轮询
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
ConnectTimeout: 1000 # 连接超时时间 没有连接上
ReadTimeout: 2000 # 数据读取超时时间 连接上了,连上之后开始计时,但读取数据需要花费很长时间
MaxAutoRetries: 1 # 最大重试次数(第一个服务)在第一次连接超时之后,在重新连接一次
MaxAutoRetriesNextServer: 0 # 最大重试下一个服务次数(集群的情况才会用到)
OkToRetryOnAllOperations: false # 是否所有操作都进行重试
熔断器
feign整合Hystrix熔断器
Feign默认也有对Hystrix的集成!
在user-consumer
配置文件里开启Hystrix熔断器
server:
port: 18082
spring:
application:
name: user-consumer
eureka:
client:
register-with-eureka: true # 是否需要把自己添加到注册中心
service-url:
defaultZone: http://127.0.0.1:7001/eureka # EurekaServer的地址
## 修改服务地址轮询策略,默认是轮询,配置之后变随机
#user-provider:
# ribbon:
# #轮询
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
# ConnectTimeout: 1000 # 连接超时时间 没有连接上
# ReadTimeout: 2000 # 数据读取超时时间 连接上了,连上之后开始计时,但读取数据需要花费很长时间
# MaxAutoRetries: 1 # 最大重试次数(第一个服务)在第一次连接超时之后,在重新连接一次
# MaxAutoRetriesNextServer: 0 # 最大重试下一个服务次数(集群的情况才会用到)
# OkToRetryOnAllOperations: false # 是否所有操作都进行重试
feign:
hystrix:
enabled: true # 开启Feign的熔断功能
新建熔断回调类UserClientFallback
package com.liu.consumer.feign;
import org.springframework.stereotype.Component;
@Component
public class UserClientFallback implements UserClient {
@Override
public String userFind(String id) {
return "服务熔断了";
}
}
在feign接口(UserClient
)里加上熔断回调
package com.liu.consumer.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
//@FeignClient(value = "要调用微服务的名字") //标记为feign接口
@FeignClient(value = "user-provider",fallback = UserClientFallback.class) //标记为feign接口
public interface UserClient {
@GetMapping("/user/find/{id}")
public String userFind(@PathVariable(value = "id") String id);
}
设置压缩数据
在user-consumer
配置文件里开启压缩数据
server:
port: 18082
spring:
application:
name: user-consumer
eureka:
client:
register-with-eureka: true # 是否需要把自己添加到注册中心
service-url:
defaultZone: http://127.0.0.1:7001/eureka # EurekaServer的地址
## 修改服务地址轮询策略,默认是轮询,配置之后变随机
#user-provider:
# ribbon:
# #轮询
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
# ConnectTimeout: 1000 # 连接超时时间 没有连接上
# ReadTimeout: 2000 # 数据读取超时时间 连接上了,连上之后开始计时,但读取数据需要花费很长时间
# MaxAutoRetries: 1 # 最大重试次数(第一个服务)在第一次连接超时之后,在重新连接一次
# MaxAutoRetriesNextServer: 0 # 最大重试下一个服务次数(集群的情况才会用到)
# OkToRetryOnAllOperations: false # 是否所有操作都进行重试
feign:
hystrix:
enabled: true # 开启Feign的熔断功能
compression:
request:
enabled: true # 开启请求压缩
response:
enabled: true # 响应压缩
压缩部分数据
```yml
server:
port: 18082
spring:
application:
name: user-consumer
eureka:
client:
register-with-eureka: true # 是否需要把自己添加到注册中心
service-url:
defaultZone: http://127.0.0.1:7001/eureka # EurekaServer的地址
## 修改服务地址轮询策略,默认是轮询,配置之后变随机
#user-provider:
# ribbon:
# #轮询
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
# ConnectTimeout: 1000 # 连接超时时间 没有连接上
# ReadTimeout: 2000 # 数据读取超时时间 连接上了,连上之后开始计时,但读取数据需要花费很长时间
# MaxAutoRetries: 1 # 最大重试次数(第一个服务)在第一次连接超时之后,在重新连接一次
# MaxAutoRetriesNextServer: 0 # 最大重试下一个服务次数(集群的情况才会用到)
# OkToRetryOnAllOperations: false # 是否所有操作都进行重试
feign:
hystrix:
enabled: true # 开启Feign的熔断功能
compression:
request:
enabled: true # 开启请求压缩
mime-types: text/html,application/xml,application/json # 设置压缩的数据类型
min-request-size: 2048 # 设置触发压缩的大小下限
#以上数据类型,压缩大小下限均为默认值
response:
enabled: true # 响应压缩
日志级别配置
在user-consumer
的配置文件中设置com.liu.consumer包下的日志级别都为debug
server:
port: 18082
spring:
application:
name: user-consumer
eureka:
client:
register-with-eureka: true # 是否需要把自己添加到注册中心
service-url:
defaultZone: http://127.0.0.1:7001/eureka # EurekaServer的地址
## 修改服务地址轮询策略,默认是轮询,配置之后变随机
#user-provider:
# ribbon:
# #轮询
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
# ConnectTimeout: 1000 # 连接超时时间 没有连接上
# ReadTimeout: 2000 # 数据读取超时时间 连接上了,连上之后开始计时,但读取数据需要花费很长时间
# MaxAutoRetries: 1 # 最大重试次数(第一个服务)在第一次连接超时之后,在重新连接一次
# MaxAutoRetriesNextServer: 0 # 最大重试下一个服务次数(集群的情况才会用到)
# OkToRetryOnAllOperations: fals