Spring Cloud Feign是一种简化开发的工具,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,不再需要手写RestTemplate和使用@HystrixCommand
写在前面:
下面将逐步介绍搭建环节,由于篇幅有限,只截取重要内容,SpringBoot项目构建方式请参考【读书笔记】2.构建SpringBoot项目,所有工程基于SpringBoot 2.0,文末也会提供项目压缩包下载
方便管理公共依赖,打包方式为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
```
需要引入spring-cloud-starter-netflix-eureka-server,然后依赖父项目,启动类和项目配置可以参考【读书笔记】3.0服务治理Spring Cloud Eureka,修改parent如下
```xml
org.cheng.demo
parent
0.0.1-SNAPSHOT
../pom.xml
```
引入依赖:
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();
}
}
引入依赖:
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的服务降级、熔断功能。
@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);
}
问题:feign-consumer项目的接口HelloService的方法与hello-service项目的HelloController的方法完全一样,假设有多个调用方,那么每个调用方自己都要单独维护一套接口,造成代码冗余
解决:通过feign的继承特性,可以抽象这些接口,服务生产者和服务消费者复用一套接口,减少服务消费者单独定义接口的工作量
创建一个工程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 {
}
不过这种继承也存在不足,如果接口有变化,必须协调下游的调用者做调整,否则调用者将无法构建项目
可以为feign客户端配置日志路径,
========》演示项目下载
下一篇API服务网关Spring Cloud Zuul