Spring Cloud Ribbon 和 Spring Cloud Hystrix 是微服务架构中实现客户端负载均衡的调用以及服务容错保护机制的基础组件。在实际的使用中,他们通常是同时出现的,那么时候有一种框架将他们整合在一起呢?Spring Cloud Feign就是一个这样的工具。他是基于Netflix Feign整合实现的,除了提供这两个的功能之外,还提供声明式的Web 服务客户端定义方式。
①首先添加依赖: 新建一个springboot项目 添加 eureka client、feign、actuator、 web、lombok的依赖
pom.xml:
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.0.8.RELEASE
com.wc.study.feign
feign_demo01
0.0.1-SNAPSHOT
feign_demo01
Demo project for Spring Boot
1.8
Finchley.SR2
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-openfeign
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
org.springframework.boot
spring-boot-maven-plugin
②:添加配置文件:指定端口 指定注册中心地址
server:
port: 8093
spring:
application:
name: consumer-feign
eureka:
instance:
hostname: localhost
client.serviceUrl.defaultZone: http://localhost:8080/eureka/
③主类上添加注解 @EnableDiscoveryClient @EnableFeignClients
package com.wc.study.feign;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class FeignDemo01Application {
public static void main(String[] args) {
SpringApplication.run(FeignDemo01Application.class, args);
}
}
④:新建一个服务调用的接口 远程的调用其他服务提供的方法:(@FeignClient(“需要添加服务调用的第三方服务的服务名”) feign支持SpringMvc的注解 在有参数的调用的时候 例如下面的情况 需要在方法的参数中 指定@RequestParam() 并且需要指定参数的名即括号内的name字段。)
package com.wc.study.feign.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Created by wangchen on 2019/1/23.
*/
@FeignClient("hello-service")
public interface HelloService {
@GetMapping("/hello")
String sayHello(@RequestParam("name") String name);
}
⑤ controller 测试类:
package com.wc.study.feign.controller;
import com.wc.study.feign.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Created by wangchen on 2019/1/23.
*/
@RestController
public class HelloController {
@Autowired
private HelloService helloService;
@GetMapping("consumer-hello")
public String sayHello(){
String name = "xiaolan";
return helloService.sayHello(name);
}
}
至于服务注册中心以及服务提供方的代码 前面已经有了 可以 服务消费 中获取到。
⑥ 运行注册中心 服务提供者 服务消费者
http://localhost:8080
⑦ 调用服务消费者测试代码
http://localhost:8093/consumer-hello 可以看到返回了正常的运行结果。
在SpringMVC中,@RequestParam和@RequestHeader注解,如果我们不指定value,则默认采用参数的名字作为其value,但是在Feign中,这个value必须明确指定,否则会报错。
在使用Student对象进行参数传递的时候,Student对象一定要有无参的构造方法,否则Spring Cloud Feign 根据json转换为Student对象时会抛出异常。
在上面的实例中我们使用的是普通的get 调用 并传递一个参数 name="xiaolan" 需要在定义的接口中 指定 @RequestParam("name") 。
下面介绍一些关于其他方式的参数传递:
package com.wc.study.feign.service;
import com.wc.study.feign.bean.Student;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
/**
* Created by wangchen on 2019/1/23.
*/
@FeignClient("hello-service")
public interface HelloService {
@GetMapping("/hello1")
String sayHello(@RequestParam("name") String name);
@PostMapping("/save")
Student save(@RequestBody Student student);
@GetMapping("/hello2")
String testHeader(@RequestHeader("name")String name,@RequestHeader("age") int age);
}
由于Feign使用的是Ribbon来实现的服务调用,我们可以直接通过配置Ribbon客户端的方式来自动义各个服务客户端调用的参数。
全局设置:ribbon.
ribbon.ConnectTimeout=2000
ribbon.ReadTimeOut=5000
指定服务配置:
HELLO-SERVICE.ribbon.ConnectTimeout=1000 .....
首先需要在配置文件中打开Feign对于Hystrix的使用
然后在指定调用服务的地方设置关于 服务降级的方法所在:
package com.wc.study.feign.service;
import com.wc.study.feign.bean.Student;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
/**
* Created by wangchen on 2019/1/23.
*/
@FeignClient(name = "hello-service",fallback = HelloServiceFallBack.class)
public interface HelloService {
@GetMapping("/hello")
String sayHello(@RequestParam("name") String name);
@PostMapping("/save")
Student save(@RequestBody Student student);
@GetMapping("/hello2")
String testHeader(@RequestHeader("name")String name,@RequestHeader("age") int age);
}
指定fallback调用的类 并且 该类交给Spring来管理。
package com.wc.study.feign.service;
import com.wc.study.feign.bean.Student;
import org.springframework.stereotype.Service;
/**
* Created by wangchen on 2019/1/23.
*/
@Service
public class HelloServiceFallBack implements HelloService {
@Override
public String sayHello(String name) {
return "error";
}
@Override
public Student save(Student student) {
return new Student("error",0);
}
@Override
public String testHeader(String name, int age) {
return "error";
}
}
经过测试发现:在调用时间超过1s的情况下 就会触发Hystrix中设置的方法。
hystrix.command.default.execution.thread.timeoutInMilliseconds=2000
可以通过这种方式来设置全局的熔断时间。
并且可以对指定的方法来进行超时时间的设置: hystrix.command.hello.execution.isolation.thread.timeoutInMilliseconds=5000
其中的hello是feign客户端中的方法名,对于相同的方法名会全部进行限制。