介绍
Spring Cloud Feign
基于Netflix Feign
实现, 整合了Spring Cloud Ribbon
和Spring Cloud Hystrix
, 除了提供这两个的功能外, 还提供了一种声明式的Web服务客户端定义方式,
在使用Spring Cloud Ribbon
时, 通常会利用它对RestTemplate
的请求拦截实现对依赖服务的接口调用, 而RestTemplate
实现了对HTTP
请求的封装处理, 形成了一套模板化的调用方法, Spring Cloud Feign
在次基础上做了进一步的封装, 定义和实现以来服务接口的定义. 在Spring Cloud Feign
的实现下, 只需要创建一个接口, 并用注解的方式配置, 即可完成对服务提供方的接口绑定.
使用
引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在启动类加入注解@EnableFeignClients
开启Spring Cloud Feign
功能
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class AnybboFeignConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(AnybboFeignConsumerApplication.class, args);
}
}
定义HelloService
接口, 通过@FeignClient
注解指定服务名来绑定服务, 然后使用Spring MVC
的注解来绑定具体该服务提供的REST
接口. 服务名不区分大小写
@FeignClient("HELLO-SERVICE")
public interface HelloService {
@GetMapping("/hello")
String hello();
}
接着在Controller
中可以直接调用HelloService
中的hello()
方法.
@RestController
public class ConsumerController {
@Resource
private HelloService helloService;
@GetMapping(value = "/feign-consumer")
public String helloConsumer() {
return helloService.hello();
}
}
最后, 在application.properties
中指定服务注册中心, 并定义自身的服务名为feign-consumer
, 以及端口
spring.application.name=feign-consumer
server.port=2112
eureka.client.service-url.defaultZone=http://localhost:1111/eureka/
启动注册中心, HELLO-SERVICE
服务, 以及feign-consumer
, 发送请求到http://localhost:2112/feign-consumer
可以实现和Ribbon
一样的效果.
Feign
实现的消费者,依然利用Ribbon
维护了针对HELLO-SERVICE
的服务列表信息, 并通过轮询实现了客户端的负载均衡, 而与Ribbon
不同的是, 通过Feign
我们只需定义服务绑定接口, 以声明式的方法,优雅而简单的实现服务调用.
参数绑定
- 在接口定义中加入请求参数,
@RequestParam, @RequestHeader 的value不能为空
, 在Spring MVC程序中, 注解会根据参数名作为默认值, 但是Feign
中绑定参数必须通过value
属性来指明具体的参数名.
@GetMapping("/hello1")
String hello1(@RequestParam("name") String name);
@GetMapping("/hello2")
String hello2(@RequestHeader("name") String name, @RequestHeader("age") Integer age);
@PostMapping("/hello3")
String hello3(@RequestBody User user);
- 请求调用
@GetMapping(value = "/feign-consumer2")
public String helloConsumer2() {
StringBuilder builder = new StringBuilder();
builder.append(helloService.hello()).append("\n");
builder.append(helloService.hello1("ANYBBO")).append("\n");
builder.append(helloService.hello2("ANYBBO1", 18)).append("\n");
builder.append(helloService.hello3(new User("ANYBBO2", 23))).append("\n");
return builder.toString();
}
继承
在使用Spring MVC
的注解绑定服务接口时, 基本上都使用复制
操作, 特别的繁琐, Spring Cloud Feign
提供了继承的特性解决复制操作.
- 抽象出
hello-service-api
项目用来定义接口
@RequestMapping("/refactor")
public interface HelloService {
@GetMapping("/hello4")
String hello4(@RequestParam("name") String name);
@GetMapping("/hello5")
User hello5(@RequestHeader("name") String name, @RequestHeader("age") Integer age);
@PostMapping("/hello6")
String hello6(@RequestBody User user);
}
- 服务提供者引入
hello-service-api
依赖, 并实现接口.在Controller中不再需要定义请求映射 @RequestMapping, 参数的注解定义在重写的时候会自动带过来
@Log4j2
@RestController
public class RefactorHelloController implements HelloService {
@Override
public String hello4(@RequestParam("name") String name) {
return "Hello " + name;
}
@Override
public User hello5(@RequestHeader("name") String name, @RequestHeader("age") Integer age) {
return new User(name, age);
}
@Override
public String hello6(@RequestBody User user) {
return "Hello " + user.getName() + ", " + user.getAge();
}
}
- 服务消费者引入
hello-service-api
依赖, 继承接口并添加@FeignClient
注解绑定服务.
@FeignClient("HELLO-SERVICE")
public interface RefactorHelloService extends HelloService {
}
- 服务调用
@Resource
private RefactorHelloService refactorHelloService;
@GetMapping(value = "/feign-consumer3")
public String helloConsumer3() {
StringBuilder builder = new StringBuilder();
builder.append(refactorHelloService.hello4("ANYBBO")).append("\n");
builder.append(refactorHelloService.hello5("ANYBBO1", 18)).append("\n");
builder.append(refactorHelloService.hello6(new User("ANYBBO2", 23))).append("\n");
return builder.toString();
}
优点:
- 将接口定义从 Controller
中剥离, 配合Maven 私有仓库
实现接口定义共享
- 实现构建期的接口绑定, 减少客户端的绑定配置
缺点:
- 由于接口在构建期间就建立了依赖, 如果接口变动会对整个项目造成影响, 假如服务提供方修改接口定义, 会导致客户端工程构建失败.
本文由 anybbo 创作,采用 知识共享署名4.0
国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Dec 17,2020