文章目录
本系列文章:
Spring(一)控制反转、两种IOC容器、自动装配、作用域
Spring(二)延迟加载、生命周期、面向切面、事务
Spring(三)异步调用、定时器、缓存
Spring(四)Spring MVC
Spring(五)Spring Boot
Spring(六)Spring Cloud----Eureka、Ribbon、Hystrix
Spring(七)Spring Cloud----Feign、Zuul和Apollo
一、服务调用Feign(Feign=Ribbon+Hystrix)
Spring Cloud Feign基于Netflix Feign实现, 整合了Spring Cloud Ribbon与Spring Cloud Hystrix
。并且,它还提供了一种声明式的 Web 服务客户端定义方式。
1、Feign采用的是基于接口的注解。
2、Feign整合了Ribbon,具有负载均衡的能力。
3、Feign整合了Hystrix,具有熔断的能力。
在使用Ribbon时,通常都会利用它对RestTemplate的请求拦截来实现对依赖服务的接口调用,而RestTemplate已经实现了对HTTP请求的封装处理。Feign在此基础上做了进一步封装,在Feign的实现下,我们只需要创建一个接口并用注解的方式来配置它,即可完成对服务提供方的接口绑定,简化了在使用Ribbon时自行封装服务调用客户端的开发量。
简而言之,Feign是一种声明式、模板化的HTTP客户端。
Feign的一个关键机制就是使用了动态代理。其具体调用过程:
- 首先,如果你对某个接口定义了@FeignClient注解,Feign就会针对这个接口创建一个动态代理;
- 接着你要是调用哪个接口,本质就是会调用Feign创建的动态代理;
- Feign的动态代理会根据你在接口上的@RequestMapping等注解,来动态构造出你要请求的服务的地址;
- 最后针对这个地址,发起请求、解析响应。
Feign的优点:
- Feign采用的是基于接口的注解;
- Feign整合了Ribbon,具有负载均衡的能力;
- 整合了Hystrix,具有熔断的能力。
Ribbon和Feign的区别:
1、都是调用其他服务的,但方式不同。
2、启动类注解不同,Ribbon是@RibbonClient,feign的是@EnableFeignClients。
3、服务指定的位置不同,Ribbon是在@RibbonClient注解上声明,Feign则是在定义抽象方法的接口中使用@FeignClient声明。
4、调用方式不同,Ribbon需要自己构建http请求,模拟http请求然后使用RestTemplate发送给其他服务,步骤相当繁琐。Feign需要将调用的方法定义成抽象方法即可。
1.1 Feign的基本使用(@EnableFeignClients + @FeignClient)
- 1、引入Eureka和Feign的相关依赖
示例:
<dependency>
<groupid>org.springfrarnework.cloud</groupid>
<artifactid>spring-cloud-starter-eureka</artifactid>
</dependency>
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-feign</artifac七Id>
</dependency>
- 2、使用@EnableFeignClients 注解
通过@EnableFeignClients 注解开启 Spring Cloud Feign 的支待功能。示例:
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class ConsumerApplication {
public static void main(String(J args) {
SpringApplication.run(ConsurnerApplication.class, args);
}
}
- 3、使用@FeignClient注解
通过@FeignClient 注解指定服务名来绑定服务, 然后再使用 Spring MVC 的注解来绑定具体该服务提供的 REST 接口。示例:
//这里服务名不区分大小写, 所以使用 hello-service和HELLO-SERVICE 都是可以的
@FeignClient("hello-service")
public interface HelloService {
@RequestMapping("/hello")
String hello();
}
- 4、调用服务
创建一个 ConsumerController 来实现对 Feign 客户端的调用。 使用@Autowired 直接注入上面定义的 HelloService 实例, 并在 helloConsumer函数中调用这个绑定了 hello-service 服务接口的客户端来向该 服务发起/hello 接口的调用。
@RestController
public class ConsumerController {
@Autowired
HelloService helloService;
@RequestMapping(value = "/feign-consumer", method = RequestMethod.GET)
public String helloConsumer() {
return helloService.hello();
}
}
- 参数绑定
现实系统中的各种业务接口比较复杂, 会在HTTP的各个位置传入各种不同类型的参数, 并且在返回请求响应的时候也可能是一个复杂的对象结构。
我们把服务提供方的接口修改下:
@RequestMapping(value= "/hellol", method= RequestMethod.GET)
public String hello(@RequestParam String name) {
return "Hello "+ name;
}
@RequestMapping(value= "/hello2", method= RequestMethod.GET)
public User hello(@RequestHeader String name, @RequestHeader Integer age) {
return new User(name, age);
}
@RequestMapping(value= "/hello3", method = RequestMethod.POST)
public String hello(@RequestBody User user) {
return "Hello "+ user.getNarne() + ", " + user. getAge();
}
服务提供方中的User类中包含name和age2个属性。
在服务消费方一般也要创建一样的实体类(此处指User类)。然后, 在 HelloService 接口中增加对上述三个新增接口的绑定声明。示例:
@FeignClient("HELLO-SERVICE")
public interface HelloService {
@RequestMapping("/hello")
String hello();
@RequestMapping(value= "/hellol", method= RequestMethod.GET)
String hello(@RequestParam("name") String name) ;
@RequestMapping(value= "/hello2", method= RequestMethod.GET)
User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age);
@RequestMapping(value = "/hello3", method= RequestMethod.POST)
String hello(@RequestBody User user);
}
1.2 Feign的属性配置
1.2.1 Ribbon配置
由于SpringCloudFeign的客户端负载均衡是通过SpringCloudRibbon实现的,所以我们可以直接通过配置Ribbon客户端的方式来自定义各个服务客户端调用的参数。
- 全局配置
全局配置的方法非常简单, 我们可以直接使用ribbon.<key>=<value>
的方式来设置ribbon的各项默认参数。 比如, 修改默认的客户端调用超时时间:
ribbon.ConnectTimeout=500
ribbon.ReadTimeout=5000
- 指定服务配置
在使用SpringCloudFeign的时候,针对各个服务客户端进行个性化配置的方式与使用SpringCloudRibbon时的配置方式是一样的, 都采用<client>. Ribbon.key=value
的格式进行设置。 此处<client>
对应的客户端名称就是@FeignClient注解中的name或value属性值。比如上个小节中对应的@FeignClient(“HELLO-SERVICE”)注解对应的客户端,我们可以设置如下属性:
HELLO-SERVICE.ribbon.ConnectTimeout=500
HELLO-SERVICE.ribbon.ReadTimeout=2000
HELLO-SERVICE.ribbon.OkToRetryOnAllOperations=true
HELLO-SERVICE.ribbon.MaxAutoRetriesNextServer=2
HELLO-SERVICE.ribbon.MaxAutoRetries=1
在配置Ribbon的超时时间时,需要 让Hystrix的超时时间大于Ribbon的超时时间
, 否则Hystrix命令超时后, 该命令直接熔断, 重试机制就没有任何意义了。
1.2.2 Hystrix配置
默认情况下,Spring CloudFeign会为将所有Feign客户端的方法都封装到Hystrix命令中进行服务保护。
- 全局配置
直接使用它的 默认配置前缀hystrix.command.default就可以进行设置, 比如设置全局的超时时间:
hystrix.command.default.execution.isolation.thread.timeoutinMilliseconds=5000
另外,在对Hystrix进行配置之前,我们需要确认feign.hystrix.enabled(默认值为true)参数没有被设置为false, 否则该参数设置会关闭 Feign客户端的Hystrix支持。
- 禁用Hystrix
在 Sprin