既然springcloud是一个微服务架构生态体系,而且上一章我们也介绍了 微服务体系中一个核心组件“服务的发现与注册”eureka,接下来我们来简单探索以下微服务体系中另一个核心组件“rpc”;在springcloud体系中实现rpc的组件有2个,一个是ribbon,另一个是feign,而且feign在底层封装了ribbon,以更友好,更灵活的形式展现在了我们眼前,所以今天我们研究的重心放在了feign身上。
(摘抄一段话,帮助大家更清晰的认识feign)
feign是netflix提供的服务间基于http的rpc调用框架,在spring cloud得到广泛应用。默认情况下,一个feign client是在hystrix断路器中执行,并利用ribbon进行软负载选择远程服务(service),所以可以想象出一个feign client的层次架构是包裹的层次,hystrix控制整个rpc从调用到方法返回,而ribbon控制从选址到socket返回;
那么什么是hystrix呢?
首先我们先置身于这样一个场景在微服务架构中,我们将业务拆分成一个个的服务,而服务与服务之间可以相互调用(RPC方式)。为了保证其高可用,单个服务又可能回事集群环境部署。所以可能存在由于网络原因或者自身的原因,并不能保证服务的100%可用,如果单个服务出现问题,调用这个服务就会出现网络延迟,此时若有大量的网络涌入,会形成任务累计,导致服务瘫痪,甚至导致服务“雪崩”。
为了解决这个问题,就出现断路器模型。
而hystrix就是Netflix的一个库并且实现了断路器模式。
(摘抄自一位网友的图)
较底层的服务如果出现故障,会导致连锁故障。当对特定的服务的调用达到一个阀值(hystric 是5秒20次) 断路器将会被打开。
断路打开后,可用避免连锁故障,fallback方法可以直接返回一个固定值。
好了,接下来我们来配置一下实际环境中我们应该怎样使用feign + hystrix?
注:基于test项目(我新建的另一个springboot项目)和demo-springboot项目;
1.打开test项目的pom.xml加入相关依赖:
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.3.4.RELEASE</version>
</dependency>
2.打开application-dev.properties加入以下内容:
#feign read timeout(10s)
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=10000
#feign read timout disable(该配置,用于禁用Hystrix的超时时间 )
#hystrix.command.default.execution.timeout.enabled=false
#关闭hystrix功能
#feign.hystrix.enabled=false
切记feign read timeout配置一个合适的超时时间,不要用默认的,我刚开始的时候没有配置,结构一直调用返回error,发现是超时了。
3.在demo-springboot中添加测试controller:
package com.example.demo.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @author xiaofeng
* @version V1.0
* @title: TestController.java
* @package: com.example.demo.controller
* @description: TODO
* @date 2018/4/3 0003 下午 2:10
*/
@RestController
@RequestMapping(value = "/test")
public class TestController {
@RequestMapping(value = "/info")
public String info(@RequestParam(value = "msg") String msg) {
return "welcome to demo-springboot: " + msg;
}
}
4.在test项目中增加rpc相关服务类:
@FeignClient(value = "demo-springboot", fallback = RpcServiceImpl.class)
public interface RpcService {
/**
* 查询test
*
* @param msg
* @return
*/
@RequestMapping(value = "/test/info", method = RequestMethod.GET)
String query(@RequestParam(value = "msg") String msg);
}
@Service
public class RpcServiceImpl implements RpcService {
/**
* 查询test
*
* @param msg
* @return
*/
@Override
public String query(String msg) {
return "error";
}
}
5.在test项目中编写测试controller:
@RestController
public class TestController {
@Autowired
RpcService rpcService;
@RequestMapping(value = "/test/index")
public String index(@RequestParam(value = "msg") String msg) {
return rpcService.query(msg);
}
}
然后再启动类中开启注解@EnableFeignClients(basePackages = {"com.xx.xx.test.service"}):表示feign 需要扫描的package路径(我的rpcService放在service包下)。
@EnableFeignClients(basePackages = {"com.xx.xx.test.service"})
@EnableAutoConfiguration
@EnableEurekaClient
@SpringBootApplication
public class Xsignal2TestApplication {
public static void main(String[] args) {
SpringApplication.run(Xsignal2TestApplication.class, args);
}
}
6.最后分别启动discover-server、demo-springboot、test三个服务
查看eureka控制面板三个服务是否都已经启动:
ok,接下来开始测试,首先是正常测试,打开浏览器:
出现的是我们理想的结果,说明我们的rpc已经走通了哦,是不是有点小鸡冻啊。
7.介绍一些常用配置
以上这种配置也是全局配置,如果我们想针对某一个接口配置,比如/hello接口,那么可以按照下面这种写法,如下:
# 设置熔断超时时间
hystrix.command.hello.execution.isolation.thread.timeoutInMilliseconds=10000
# 关闭熔断功能
hystrix.command.hello.execution.timeout.enabled=false
# 配置请求GZIP压缩
feign.compression.request.enabled=true
# 配置响应GZIP压缩
feign.compression.response.enabled=true
# 配置压缩支持的MIME TYPE
feign.compression.request.mime-types=text/xml,application/xml,application/json
# 配置压缩数据大小的下限
feign.compression.request.min-request-size=2048
注意点:
1.有些公共的组件抽出来其他模块的maven依赖,此时要在使用的项目中加载此jar包的spring component以及feign组件,仅仅依靠@ComponentScan是不够的,还需要在@EnableFeignClients(basePackages = {"com.xx.xx.test.service"})中标注basekPackages。
2.springcloud feign 注入bean null问题
解决办法:
1. 如果swagger版本是v1.x,那么请参考:
2. 如果swagger版本是v2.x,那么请将升级swagger版本到2.5.0以上即可。
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.5.0</version>
</dependency>
3.feign rpc返回的json对象转换失败
1.复杂对象转换失败(Response<pageList<obj>)
2.接口返回对象转换:
ResponseModel<Long> responseModel = JsonUtils.json2Obj(data, new TypeReference<ResponseModel<Long>>(){});
new TypeReference<ResponseModel<Long>>(){}