SpringCloud Netflix Feign

调用其它机器上的服务(远程调用)有2种技术:REST、RPC。 REST 注入RestTempalte,服务提供者的url要写成RESTful风格,在url中传递参数。 如果参数很多,url会有一长串/,且只能传递数...

调用其它机器上的服务(远程调用)有2种技术:REST、RPC。

REST

注入RestTempalte,服务提供者的url要写成RESTful风格,在url中传递参数。

如果参数很多,url会有一长串/,且只能传递数值、字符串之类,不能传递整个对象(可以以多个属性的方式传过去,但显然不方便)。

REST只适合传递简单类型、个数很少的参数。

简单,基于HTTP协议,通用性强,但性能低。

面向资源(url)。

RPC

远程过程调用(Remote Procedure Call),远程调用其它服务中的过程(函数)。

不把参数直接写在url中,所以不存在url很难看的问题。通过参数表传递参数,可以传递任何类型的参数。

屏蔽跨进程调用函数(服务)的各类复杂细节,用接口来映射(代理)远程服务,使得远程调用也是面向对象的。

使用比TEST稍微复杂些,但功能比REST更多、性能更高。

RPC只是一个统称,有多种实现框架,大部分基于UDP协议,少数基于HTTP协议。

Feign是RPC的一个框架,基于HTTP协议。

和eureka、ribbon一样,也是netflix家的开源框架,也被SpringCloud整合了。


  

Feign的使用

以用户服务调用订单服务为例。

1、服务消费者

(1)pom.xml

    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
      <version>2.2.1.RELEASE</version>
    </dependency>

(2)引导类

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients  //开启Fegin客户端
public class UserServer {
    @Bean
    @LoadBalanced  //使用Ribbon实现负载均衡
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

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

}

(3)新建包com.chy.feign,包下新建接口OrderFeignService

@FeignClient("order-server") //作为一个Feign客户端,参数指定要调用的服务名称,会自动使用负载均衡找到合适的节点
public interface OrderFeignService {

    @GetMapping("/order/findAllByUserId") //要调用的地址,不必使用RESTful风格
    List<Order> findOrdersByUserId(@RequestHeader("user_id") Integer user_id); //使用参数表传递参数

}

一个要调用的服务对应一个接口(一个Feign客户端),如果要调用多个服务,需要写多个接口。

只需要告知服务名(负载均衡找到合适的节点)、映射地址(要调用的地址)。

使用参数表传递参数,在每个参数前都加注解。

如果只传递数值、字符串等普通类型:

  • 映射地址使用@GetMapping、@PostMapping标注都行,但需要和服务提供者中的保持一致。
  • 参数使用@Request("变量名")、@RequestParam("变量名")标注都行,都是加到请求头中的,必须要指明变量名。也可以使用Restful风格的映射地址+@PathVariable。

如果要传递对象:

  • 参数数据量大,需要使用@PostMapping,服务提供者中对应的映射也要使用@PostMapping
  • 对象数据量大,要放到RequestBody中传递,所以对象只能使用@RequestBody标注,不标注变量名

和Mapper接口、动态代理类似,但只需要我们写映射接口,Feign会自动帮我们实现。

(4)在controller中调用

@Controller
@RequestMapping("/user")
public class UserController {
    //注入要调用的Feign客户端,不使用RestTemplate
    private OrderFeignService orderFeignService;

    @Autowired
    public void setOrderFeignService(OrderFeignService orderFeignService) {
        this.orderFeignService = orderFeignService;
    }

    //根据用户id查找用户所有订单
    @GetMapping("/order/{user_id}")
    @ResponseBody
    public List<Order> findOrdersByUserId(@PathVariable Integer user_id){
        //调用Feign客户端(接口)的方法,传入需要的参数
        List<Order> orderList = orderFeignService.findOrdersByUserId(user_id);
        return orderList;
    }

}

把服务调用写成(映射成)接口,使得服务调用也是面向接口、面向对象编程的。

Feign比REST要麻烦点(因为要写Feign接口),但Feign(RPC)性能高。

Feign(RPC)只需要我们定义映射接口,会自动实现映射,隐藏了把参数封装到请求中、网络通信、对象序列化、反序列化等细节,我们只需关注服务调用本身。

实际上,不管使用REST、还是Feign,都不建议直接在controller中调用其它业务,

尽量使用三层架构,在service层调用Feign接口来处理业务,再由controller调用service。


2、服务提供者

@Controller
@RequestMapping("/order")
public class OrderController {

    //根据用户id查找该用户的所有订单
    @GetMapping("/findAllByUserId")  //请求方式、映射地址都要和消费者中的Feign接口对应
    @ResponseBody
    public List<Order> findAllByUserId(@RequestHeader("user_id") Integer user_id){ //参数表要和消费者中的Feign接口对应
        //一些列操作
        //......
        return orderList;
    }

}

映射地址、请求方式要与消费者中的保持一致。

消费者使用@RequestHeader("变量名")传递,提供者就使用@RequestHeader("变量名")来接收参数,

方式要相同,怎么传,就怎么接,传什么类型,就使用相同的类型来接。

如果要传递对象,比如要传递User对象,那双方肯定都要提供User这个实体类。

  • 发表于 2020-02-15 11:00
  • 阅读 ( 25 )
  • 分类:网络文章

条评论

请先 登录 后评论
不写代码的码农
小编

篇文章

作家榜 »

  1. 小编 文章
返回顶部
部分文章转自于网络,若有侵权请联系我们删除