声明式调用Spring Cloud Feign

介绍

Spring Cloud Feign是一种简化开发的工具,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,不再需要手写RestTemplate和使用@HystrixCommand

快速入门

写在前面:
下面将逐步介绍搭建环节,由于篇幅有限,只截取重要内容,SpringBoot项目构建方式请参考【读书笔记】2.构建SpringBoot项目,所有工程基于SpringBoot 2.0,文末也会提供项目压缩包下载

项目结构预览
声明式调用Spring Cloud Feign_第1张图片

1.搭建一个公共的父项目parent

方便管理公共依赖,打包方式为POM

```xml
	pom
    
    
        
        
            org.springframework.boot
            spring-boot-starter
        
        
        
            org.springframework.boot
            spring-boot-devtools
            runtime
        
        
        
            org.projectlombok
            lombok
            true
        
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    
```

2.搭建注册中心eureka-server

需要引入spring-cloud-starter-netflix-eureka-server,然后依赖父项目,启动类和项目配置可以参考【读书笔记】3.0服务治理Spring Cloud Eureka,修改parent如下

```xml
    
        org.cheng.demo
        parent
        0.0.1-SNAPSHOT
        ../pom.xml 
    
```

3.创建一个服务提供者hello-service

引入依赖:
spring-boot-starter-web,spring-cloud-starter-netflix-eureka-client 
然后创建一个HelloController,提供几个简单接口,如下
@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello()  {
        return "Hello World";
    }
    
	@GetMapping("/hello1")
    public String hello(@RequestParam("name") String name) {
        return "Hello " + name;
    }

    @GetMapping("/hello2")
    public User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age) {
        return new User(name, age);
    }

    @PostMapping("/hello3")
    public String hello(@RequestBody User user) {
        return "Hello " + user.getName() + ", " + user.getAge();
    }
}

4.创建服务消费者feign-comsumer,声明式调用

引入依赖:
spring-boot-starter-web,spring-cloud-starter-netflix-eureka-client,spring-cloud-starter-openfeign
在启动类贴上@EnableFeignClients,表明这是一个Feign客户端,开启Feign支持
再创建一个ConsumerController,引入HelloService服务,示例代码如下

@RestController
public class ConsumerController {
	@Autowired
    private HelloService  helloService;

    @GetMapping("/feign-consumer")
    public String helloConsumer() {
        return helloService.hello();
    }
}

本项目还需创建一个接口HelloService和对应的服务降级实现,内容如下

// feign客户端绑定服务(服务名不区分大小写)
@FeignClient(value = "HELLO-SERVICE", fallback = HelloServiceFallback.class)
public interface HelloService {
	 @RequestMapping("/hello")
	 String hello();
 }
 
// 消费失败时服务降级
@Component
public class HelloServiceFallback implements HelloService {
    @Override
    public String hello() {
        return "/hello, error";
    }
}

至此,一个简单的服务注册发现,声明式调用(本地化,引入HelloService)示例已完成,
此消费者同时拥有Ribbon客户端负载均衡和Hystrix的服务降级、熔断功能。

4.1参数绑定

@RequestParam(value=“xxx”),绑定请求中的Request参数
@RequestHeader(value=“xxx”),绑定请求中的Header信息
@RequestBody,绑定请求中的RequestBody或者请求响应体为对象
注:@GetMaping和@PostMaping在此版本可正常使用,当请求体为对象时,应保证存在默认构造函数
示例代码如下,

   @FeignClient(value = "HELLO-SERVICE", fallback = HelloServiceFallback.class)
public interface HelloService {

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

    @RequestMapping(value = "/hello1", 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);
}

4.2继承特性

问题:feign-consumer项目的接口HelloService的方法与hello-service项目的HelloController的方法完全一样,假设有多个调用方,那么每个调用方自己都要单独维护一套接口,造成代码冗余
解决:通过feign的继承特性,可以抽象这些接口,服务生产者和服务消费者复用一套接口,减少服务消费者单独定义接口的工作量

5.重构Hello-service和feign-consumer

创建一个工程hello-service-api,里面就一个接口,内容与上一小节的代码块相同,但不需要@FeignClient
hello-service和feign-consumer同时引入依赖hello-service-api
对hello-service而言,需要创建实现hello-service-api里面的接口,并且参数列表也要使用注解(缺陷?),内容如下

// feign的继承特性示例
// 实现hello-service-api的接口后,原本hello-service的controller不再需要@RequestMapping
@RestController
@Slf4j
public class RefactorHelloControllerImpl implements HelloService {

    @Override
    public String hello(@RequestParam("name") String name) {
        log.info("/hello4,{}", name);
        return "Hello " + name;
    }

    @Override
    public User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age) {
        log.info("/hello5,{},{}", name, age);
        return new User(name, age);
    }

    @Override
    public String hello(@RequestBody User user) {
        log.info("/hello6,{}", user);
        return "Hello " + user;
    }
}

对feign-consumer而言,代码简化成(此处应有掌声)

 // 继承hello-service-api的HelloService后,对服务消费者而言,不再需要像本地的HelloService定义接口
@FeignClient("HELLO-SERVICE")
public interface RefactorHelloService extends org.cheng.feign.service.HelloService {
}

不过这种继承也存在不足,如果接口有变化,必须协调下游的调用者做调整,否则调用者将无法构建项目

6.其他配置

可以为feign客户端配置日志路径,

  • 1.配置文件添加logging.level.=DEBUG
  • 2.启动类添加 feign.Logger.level的bean

========》演示项目下载

下一篇API服务网关Spring Cloud Zuul

你可能感兴趣的:(SpringCloud,读书笔记)