您的位置:首页 > 编程语言 > Java开发

SpringCloud微服务知识整理六:声明式服务调用 Spring Cloud Feign

2019-01-09 16:37 1206 查看

什么是Spring Cloud Feign

Spring Cloud Feign 是基于 Netflix Feign 实现的,整合了 Spring Cloud Ribbon 和 Spring Cloud Hystrix,除了提供这两者的强大功能之外,还提供了一种声明式的 Web 服务客户端定义方式

一、快速入门

1、创建一个 Spring Boot 基础工程,取名为 feign-consumer,并在 pom.xml 中引入 spring-cloud-starter-eureka 和 spring-cloud-starter-feign 依赖。

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>

2、在主类上通过 @EnableFeignClients 注解开启 Spring Cloud Feign 的支持功能。

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class FeignConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(FeignConsumerApplication.class, args);
}
}

3、定义 HelloService 接口,通过 @FeignClient 注解指定服务名来绑定服务,然后再使用 Spring MVC 的注解来绑定具体该服务提供的 REST 接口。

@FeignClient(value = "hello-service")
public interface HelloService {
@RequestMapping(value = "/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();
}
}

5、在 application.properties 中指定注册中心,并定义自身的服务名为 feign-consumer

spring.application.name=feign-consumer
server.port=9001

eureka.client.service-url.defaultZone=http://localhost:1111/eureka/

6、验证
启动 eureka-server 和 两个hello-service,然后启动 feign-consumer,发送请求到 http://localhost:9001/feign-consumer,正确返回。
与 Ribbon 不同的是,通过 Feign 我们只需定义服务绑定接口,以声明式的方法,优雅而简单地实现了服务调用。

二、参数绑定

传入参数和反回复杂对象的用法:
1、先扩展一下服务提供方 hello-service 。增加下面这些接口定义。

@RequestMapping(value = "/hello1", method = RequestMethod.GET)
public String hello1(@RequestParam String name){
return "HELLO " + name;
}

@RequestMapping(value = "/hello2", method = RequestMethod.GET)
public User hello2(@RequestHeader String name, @RequestHeader Integer age){
return new User(name, age);
}

@RequestMapping(value = "/hello3", method = RequestMethod.POST)
public String hello3(@RequestBody User user){
return "HELLO," + user.getName()+","+user.getAge();
}

2、定义User 对象,需要注意,这里必须要有User 的默认构造函数。不然,Spring Cloud Feign 根据 JSON 字符串转换 User 对象会抛出异常。

public class User {
private String name;

private Integer age;

public User() {
}

public User(String name, Integer age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

3、在 feign-consumer 中创建与上面一样的 User 类。
4、在 HelloService 接口中增加对上述三个新增接口的绑定声明。

@FeignClient(value = "hello-service")
public interface HelloService {

@RequestMapping(value = "/index")
String hello();

@RequestMapping(value = "/hello1", method = RequestMethod.GET)
String hello1(@RequestParam(value = "name") String name);

@RequestMapping(value = "/hello2", method = RequestMethod.GET)
User hello2(@RequestParam(value = "name") String name, @RequestHeader(value = "age") Integer age);

@RequestMapping(value = "/hello3", method = RequestMethod.POST)
String hello3(@RequestBody User user);
}

5、在 ConsumerController 中新增一个 /feign-consumer2 接口

@RestController
public class ConsumerController {

@Autowired
HelloService helloService;

@RequestMapping(value = "feign-consumer", method = RequestMethod.GET)
public String helloConsumer(){
return helloService.hello();
}

@RequestMapping(value = "/feign-consumer2", method = RequestMethod.GET)
public String helloConsumer2(){
StringBuilder sb = new StringBuilder();
sb.append(helloService.hello1("didi")).append("\n");
sb.append(helloService.hello2("didi", 18)).append("\n");
sb.append(helloService.hello3(new User("didi", 20))).append("\n");
return sb.toString();
}
}

6、验证
http://localhost:9001/feign-consumer2 ,触发 HelloService 对新增接口的调用

三、继承特性

通过 Spring Cloud Feign 的继承特性来实现 REST 接口定义的复用
1、为了能够复用 DTO 与接口定义,我们先创建一个基础的 Maven 工程,命名为 hello-service-api。
2、在 hello-service-api 中需要定义可同时复用于服务端与客户端的接口,我们要使用到 Spring MVC 的注解,所以在 pom.xml 中引入 spring-boot-starter-web 依赖
3、将 User 对象复制到 hello-service-api 工程中。
4、在 hello-service-api 工程中创建 HelloService 接口

@RequestMapping(value = "/refactor")
public interface HelloService {

@RequestMapping(value = "/hello4", method = RequestMethod.GET)
String hello4(@RequestParam(value = "name") String name);

@RequestMapping(value = "/hello5", method = RequestMethod.GET)
User hello5(@RequestHeader(value = "name") String name, @RequestHeader(value = "age") Integer age);

@RequestMapping(value = "/hello6", method = RequestMethod.POST)
String hello6(@RequestBody User user);
}

5、执行命令 mvn install 将该模块构建到本地仓库。
6、对 hello-service 进行重构,在 pom.xml 的 dependency 节点中,新增对 hello-service-api 的依赖。

<dependency>
<groupId>com.didispace</groupId>
<artifactId>hello-service-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

7、创建 RefactorHelloController 类实现 hello-service-api 中定义的 HelloService 接口,并参考之前的 HelloController 来实现这三个接口

@RestController
public class RefactorHelloController implements HelloService {

@Override
public String hello4(@RequestParam(value = "name") String name) {
return "HELLO " + name;
}

@Override
public User hello5(@RequestHeader(value = "name") String name, @RequestHeader(value = "age") Integer age) {
return new User(name, age);
}

@Override
public String hello6(@RequestBody User user) {
return "HELLO," + user.getName()+","+user.getAge();
}
}

8、完成了服务提供者的重构,接下来在服务消费者 feign-consumer 的 pom.xml 文件中,如在服务提供者一样,新增对 hello-service-api 的依赖。
9、创建 RefactorHelloService 接口,并继承 hello-service-api 包中的 HelloService 接口,然后添加 @FeignClient 注解来绑定服务。

@FeignClient (value="Hello-Service")
public interface RefactorHelloService extends HelloService{
}

10、在ConsumerController中注入RefactorHelloService 并新增一个请求来触发

@RequestMapping(value = "/feign-consumer3",method=RequestMethod.GET)
public String helloConsumer3(){
StringBuilder sb = new StringBuilder();
sb.append(refactorHelloService.hello("MIMI")).append("\n");
sb.append(refactorHelloService.hello("MIMI","123456")).append("\n");
sb.append(refactorHelloService.hello(new com.didispace.dto.User("MIMI","123456"))).append("\n");
return sb.toString();
}

四、Ribbon配置

1、全局配置

ribbon.ConnectTimeout=500
ribbon.ReadTimeout=5000

2、指定服务配置

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

3、重试机制
默认实现

五、Hystrix配置

1、全局配置

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000
#关闭 Hystrix 功能
#feign.hystrix.enabled=false#关闭熔断功能
#hystrix.command.default.execution.timeout.enabled=false

2、禁用Hystrix

feign.hystrix.enabled=false

针对某个客户端关闭 Hystrix ,通过使用 @Scope(“prototype”) 注解为指定的客户端配置 Feign.Builder 实例
构建一个关闭 Hystrix 的配置类

@Configuration
public class DisableHystrixConfiguration {

@Bean
@Scope("prototype")
public Feign.Builder feignBuilder(){
return Feign.builder();
}

}

在 HelloService 的 @FeignClient 注解中,通过 configuration 参数引入上面实例的配置

@FeignClient(value = "SERIVCE-USER",configuration = DisableHystrixConfiguration.class)
@Service
public interface HelloService {
···
}

4、指定命令配置
对 /hello 接口的熔断时间的配置

hystrix.command.hello.execution.isolation.thread.timeoutInMilliseconds=5000

5、服务降级配置
对 feign-consumer 工程进行改造,为HelloService接口实现一个服务降级类

@Component
public class HelloServiceFallBack implements HelloService {
@Override
public String hello() {
return "error";
}

@Override
public String hello(@RequestParam("name") String name) {
return "error";
}

@Override
public User hello(@RequestHeader("name") String name,@RequestHeader("password") String password) {
return new User("未知","0");
}

@Override
public String hello(User user) {
return "error";
}
}

在服务绑定接口 HelloService 中,通过 @FeignClient 注解的 fallback 属性来指定对应的服务降级实现类

@FeignClient(value = "SERIVCE-USER",fallback = HelloServiceFallBack.class)
@Service
public interface HelloService {

@RequestMapping("/hello")
String hello();

@GetMapping(value = "/hello1")
String hello(@RequestParam("name") String name);

@GetMapping(value = "/hello2")
User hello(@RequestHeader("name") String name,@RequestHeader("password") String password);

@PostMapping(value = "/hello3")
String hello(@RequestBody User user);
}

六、其他配置

1、请求压缩

feign.compression.request.enabled=true
feign.compression.response.enabled=true
#设置压缩的大小下限,超过的才进行压缩,以下配置为默认值
feign.compression.request.mime-types=text/xml,application/xml,application/json
feign.compression.request.min-request-size=2048

2、日志配置

logging.level.com.didispace.web.HelloService=DEBUG

feign-consumer 启动类配置

@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class SpringcloudFeignApplication {

@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}

public static void main(String[] args) {
SpringApplication.run(SpringcloudFeignApplication.class, args);
}
}

也可以通过实现配置类,然后在具体的Feign 客户端来指定配置类以实现是否要调整不同的日志界别

@Configuration
public class FullLogConfiguration {

@
20000
Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}

}
@FeignClient(name="HELLO_SERVICE",configuration = FullLogConfiguration.class
public interface HelloService{
...
}

Feign的Logger级别:
NONE
BASIC
HEADERS
FULL

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: