SpringCould Feign学习
Spring Cloud Feign远程调用
RestTemplate这种方式是否还有优化空间呢?从复用、管理、可读性继续宁考虑
- Feign 的英文表意为“假装,伪装,变形”, 是一个http请求调用的轻量级框架,是以Java接口的方式调用Http接口,而不用像Java中通过封装HTTP请求报文的方式直接调用。
- Feign通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观。
- Feign封装了RestTemplate
怎么实现的?
- Feign通过注解将请求相关信息封装到接口中,当实际调用接口的时候,传入参数,根据参数加注解转化成真正的请求路径,然后使用RestTemplate发送请求,本质上,还是Http请求的发送,只不过这种相对而言比较直观。
配置
导入依赖feign的starter
<!--配置feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
启动引导类加@EnableFeignClients注解
Feign中已经自动集成Ribbon负载均衡
@SpringCloudApplication
@EnableFeignClients//开启Feign功能
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class,args);
}
}
编写FeignClient接口,使用SpringMVC的注解
- 在consumer_service中编写Feign客户端接口UserService
- Feign会通过动态代理,帮我们生成实现类。
- 注解@FeignClient声明Feign的客户端接口,需指明服务名称
- 接口定义的方法,采用SpringMVC的注解。Feign会根据注解帮我们逆向生成URL地址然后请求
@FeignClient("user-service")//指定feign调用的服务
public interface UserService {
@RequestMapping("/user/findById")
User findById(@RequestParam("id") Integer id);
}
在Controller中注入Feign接口,直接调用,无需实现类
@RestController
public class FeignConsumerController {
@Autowired
private UserService userService;
@RequestMapping("/feignconsumer/{id}")
@HystrixCommand(fallbackMethod = "queryIdByFallBack")
public User findByIdRibbon(@PathVariable("id") Integer id){
return userService.findById(id);
}
public User queryIdByFallBack(Integer id){
User user = new User();
user.setNote("对不起,网络太拥挤了");
return user;
}
}
访问接口测试
踩坑: provider中的提供服务服务函数使用restful风格会报错
后续学习:因为在接口中使用的不是restful的风格
整合负载均衡
consumer中配置
-
负载均衡是远程过程调用必备的要素。Feign本身集成了Ribbon,因此不需要额外引入依赖,也不需要再注册RestTemplate对象。即可无感知使用负载均衡这一特性。
-
Fegin内置Ribbon默认设置了连接超时,是1000毫秒(1秒)。和读取超时时间。我们可以通过手动配置来修改。Ribbon内部有重试机制,一旦超时,会自动重新发起请求。如果不希望重试,可以修改。
# 配置熔断器超时时间
# 连接超时时长
ribbon.ConnectTimeout: 6000
# 读取数据超时时长
ribbon.ReadTimeout: 6000
# 当前服务器的重试次数【针对请求】
ribbon.MaxAutoRetries: 0
# 重试多少次服务【针对服务】
ribbon.MaxAutoRetriesNextServer: 0
# 是否对所有的请求方式都重试
ribbon.OkToRetryOnAllOperations: false
整合熔断器
Feign本身也集成Hystrix熔断器,starter内查看。
服务降级方法实现步骤:
- 在配置文件application.yml中开启feign熔断器支持
- 编写FallBack处理类,实现FeignClient客户端接口
- 在@FeignClient注解中,指定FallBack处理类。
- 测试服务降级效果
实现过程:
-
在配置文件application.yml中开启feign熔断器支持:默认关闭
feign.hystrix.enabled: true # 开启Feign的熔断功能
-
定义一个类UserServiceFallBack,实现刚才编写的UserFeignClient,作为FallBack的处理类
@Component//需要注意:一定要注入Spring 容器 public class UserServiceFallBack implements UserService { @Override public User findById(Integer id) { User user = new User(); user.setId(id); user.setUsername("用户不存在!!!"); return user; } }
-
在@FeignClient注解中,指定FallBack处理类。。
@FeignClient(value = "user-service",fallback = UserServiceFallBack.class) public interface UserService { @RequestMapping("/user/findById") User findById(@RequestParam("id") Integer id); }
-
重启测试:关闭user_service服务,然后在页面访问;http://localhost:8080/feignConsumer/2
实测设置服务提供者延时三秒,访问直接熔断,(已经加了上面的ribbon配置): 猜测问题的根源在于没有访问通过feign的路径,那怎么可能生效呢(测试后还是不行,不是路径的问题)
请求压缩和响应压缩
SpringCloudFeign支持对请求和响应进行GZIP压缩,以提升通信过程中的传输速度。
为什么RPC远程调用的方式性能更高?传输的数据量小
通过配置开启请求与响应的压缩功能:
# 开启请求压缩
feign.compression.request.enabled: true
# 开启响应压缩
feign.compression.response.enabled: true
也可以对请求的数据类型,以及触发压缩的大小下限进行设置
# 设置压缩的数据类型
feign.compression.request.mime-types: text/html,application/xml,application/json
# 设置触发压缩的大小下限
feign.compression.request.min-request-size: 2048
配置日志级别
在发送和接收请求的时候,Feign定义了日志的输出定义了四个等级:这里我们配置测试一下。
级别 | 说明 |
---|---|
NONE | 不做任何记录 |
BASIC | 只记录输出Http 方法名称、请求URL、返回状态码和执行时间 |
HEADERS | 记录输出Http 方法名称、请求URL、返回状态码和执行时间 和 Header 信息 |
FULL | 记录Request 和Response的Header,Body和一些请求元数据 |
实现步骤:
- 在application.yml配置文件中开启日志级别配置
- 编写配置类,定义日志级别bean。
- 在接口的@FeignClient中指定配置类
- 重启项目,测试访问
实现过程:
-
在consumer_service的配置文件中设置com.ahu包下的日志级别都为debug
-
# com.itheima 包下的日志级别都为Debug logging.level: com.ahu: debug
-
-
在consumer_service编写配置类,定义日志级别
-
@Configuration public class FeignConfiguration { @Bean public Logger.Level feignLoggerLevel(){ //记录所有请求和响应的明细,包括头信息,请求体,元数据 return Logger.Level.FULL; } }
-
-
在consumer_service的FeignClient中指定配置类
-
@FeignClient(value="user-service",fallback = UserServiceFallBack.class,configuration = FeignConfig.class) public interface UserService { @RequestMapping("/user/{id}") User queryById(@PathVariable("id") Long id); }
-
-
重启项目,即可看到每次访问的日志
必须访问通过feign的路径