手写不易,对您有帮助。麻烦一键三连。也欢饮各位大料指正,交流。
微服务feign组件学习
1.概念
当我们使用微服务架构后,服务之间的调用就是我们需要额外关注的事情,springCloud Alibaba为我们提供了服务调用的两个核心组件Feign、Ribbon。
- Feign: 微服务间的通信都是通过
Feign
这种HttpClient客户段进行调用 - Ribbon:负责服务间调用之前的负载均衡
1.1 feign 概念
Feign是Neflix开发的声明式、模板化的HTTP客户端,可帮助我们更加便捷、优雅地调用HTTP API。Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。
Sping cloud openfeign 对Feign进行了增强,使其支持Spring MVC注解,另外还整合了Ribbon和Nacos,从而使得Feign的使用更加方便。
1.2 Ribbon概念
Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具。基于消费端这边先从注册中心拿到服务列表,直接在消费端就做了负载均衡,它是一种基于消费端的负载均衡。与之区别的是而基于服务端的负载均衡就像nginx(软件)和F5(硬件)这样的对服务器做反向代理的方式。
在springCloud Alibaba 中Feign默认已经集成了Ribbon。如果想要单独使用可以考虑 RestTemplate+@LoadBalanced注解的形式
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced //使用Ribbon让RestTemplate负载均衡
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
后面所有使用Feign的操作则默认集成了Ribbon,此处不在赘述。
2.使用
项目基于spring-cloud版本Hoxton.SR8创建。
2.1 集成feign
2.1.1 maven依赖
<!--集成openFeign接口 其引入了feign组件和Ribbon组件-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.1.2 项目结构
如上项目结构,customer模块feign调用order,并提供了一个order-api的feign接口依赖层。
2.2 使用
2.2.1 定义feign接口
@FeignClient(name = "${com.xiu.order.service}", primary = false,decode404 = false)
public interface OrderClient {
@GetMapping("/provider/order/{orderPath}/create")
String create(@PathVariable(value = "orderPath") String orderPath);
//get请求 多于1个参数,则必须写@RequestParam注解
@GetMapping("findOrder")
Order findOrder(@RequestParam(name = "pName") String name,
@RequestParam(name = "pAge") Integer age);
//TODO 无法正常传参
//@RequestParam后面是自定义参数类型将不会封装到接口的方法参数中
@GetMapping("getOrder1")
Order getOrder(@RequestParam("Order") Order Order);
//TODO 无法正常传参
//feign将会把url拼接成url?name=xx&age=yy&address=zz(address字符串形式)
//这个address将会导致接口那边在获取address时,不能正常封装成Address对象而导致报错
@GetMapping("getOrder2")
Order getOrder1(@RequestParam(name = "name") String name,
@RequestParam(name = "age") Integer age
,@RequestParam(name = "address") Address address);
//可以使用Map封装(远程接口使用@RequestBody Map来接收(address属性能正常接收到))
@PostMapping("getOrder")
Map<String,Object> getOrder2(Map<String,Object> map);
//不能使用超过1个@RequestBody
@PostMapping("addOrder")
Order addOrder(@RequestBody Order order, @RequestParam("pAge") Integer age);
//TODO 无法正常传参
@RequestParam后面是自定义参数Address将不会封装到接口的方法参数中
@PostMapping("addOrder2")
Order addOrder2(@RequestBody Order Order,@RequestParam("addr") Address addr);
// 多于1个参数,则必须写@RequestParam注解(并且必须写value)
// feign拼接url?ids=1%2C2%2C3 (%2C,即逗号)
@PostMapping("checkOrder")
Order checkOrder(@RequestBody Order order, @RequestParam("ids") Integer[] ids);
// 多于1个参数,则必须写@RequestParam注解(并且必须写value)
// feign拼接url??ids=1&ids=2&ids=3
@PostMapping("checkOrder2")
Order checkOrder2(@RequestBody Order order, @RequestParam("ids") List<Integer> ids);
}
#配置文件中声明服务名 用于@FeignClient 的name属性
com:
xiu:
order:
service: order-server
图上定义了一个feign接口并给出了feign的常用方式。需要关注的一点是接口需要使用**@FeignClient**注解修饰
name属性设置服务名(负载均衡组件会根据服务名获取对应的注册中心的所有服务对应的服务列表)。
2.2.2 消费端服务调用
public class FeignTestServiceImpl implements FeignTestService {
@Resource
private OrderClient orderClient;
@Override
public String sayHello() {
String orderPath = orderClient.create("aaaa");
log.info(orderPath);
return "hello nacos!!!";
}
}
在customer模块中可以像使用其自己的服务一样使用feign服务OrderClient。
2.2.3 消费端扫描feign接口
@Slf4j
@SpringBootApplication(scanBasePackages = {
"com.xiu"})
//扫描指定包路径下的feignClient接口
//不指定 默认回扫描当前类CustomerApp所在的路径为basePackages
@EnableFeignClients(basePackages = {
"com.xiu"})
@EnableDiscoveryClient
public class CustomerApp {
public static void main(String[] args) {
SpringApplication.run(CustomerApp.class, args);
}
}
注意事项
消费者模块启动类上使用@EnableFeignClients注解后一定要指明Feign接口所在的包路径。 所以这里推荐你们在开发中所有feign模块最好能统一包名前缀。
2.3 参数配置
2.3.1 @FeignClient参数配置
属性 | 说明 |
---|---|
name | 指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现 |
url | url一般用于调试,可以手动指定@FeignClient调用的地址 |
decode404 | 当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignExcepti |