远程调用
何为远程调用?例如:单体服务时,A模块的功能涉及到引用B模块的功能,那我们需要在A模块中注入B模块的相关服务类并调用其方法;那么同样的逻辑在微服务体系下,就会变成了A服务的功能需要调用B服务的功能,这就形成了服务间调用,也称为远程调用。
目前来说,微服务体系已经相当成熟,SpringCloud体系中也提供了完善的、便捷的工具。Feign 和 OpenFeign。 本文主要以 OpenFeign 为主,目前主流也推荐使用OpenFeign.
Feign 和 OpenFeign
OpenFeign 组件的前身是 Netflix Feign 项目,它最早是作为 Netflix OSS 项目的一部分,由 Netflix 公司开发。后来 Feign 项目被贡献给了开源组织,于是才有了我们今天使用的 Spring Cloud OpenFeign 组件。
Feign 和 OpenFeign 有很多大同小异之处,不同的是 OpenFeign 支持 MVC 注解。可以认为 OpenFeign 为 Feign 的增强版。
简单总结下 OpenFeign 能用来做什么:
- OpenFeign 是声明式的 HTTP 客户端,让远程调用更简单。
- 提供了HTTP请求的模板,编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息
- 整合了Ribbon(负载均衡组件)和 Hystix(服务熔断组件),不需要显示使用这两个组件
- Spring Cloud Feign 在 Netflix Feign的基础上扩展了对SpringMVC注解的支持
快速使用
引入依赖
<!-- openfeign 远程调用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
代码编写
接口类
- 使用 注解 @FeignClient,将服务间调用 封装为 MVC 中的服务类 供调用者使用
package com.learning.springcloud.order.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* name; 服务名
* path: 调用REST接口的根路径
*/
@FeignClient(name = "stock-service", path = "/stock")
public interface StockFeignService {
// @RestController
// @RequestMapping("/stock")
// public class StockController {
//
// @Value("${server.port}")
// String serverPort;
//
// @RequestMapping("/reduct")
// public Object reductStock() {
// System.out.println(serverPort + ":扣减库存成功了");
// return "reduct stock success. stock service port:" + serverPort;
// }
// }
@RequestMapping("/reduct")
String reductStock(); // 真实返回的类型是啥 feign接口就是啥类型 这里是String
}
调用者
- 上述步骤已将 服务间调用进行MVC服务类封装
- 使用的地方则类似MVC,直接@Autowired注入使用即可
package com.learning.springcloud.order.controller;
import com.learning.springcloud.order.feign.StockFeignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
StockFeignService stockFeignService;
@RequestMapping("/add")
public Object addOrder() {
// System.out.println("下单成功!!!");
// String templateForObject = restTemplate.getForObject("http://stock-service/stock/reduct", String.class);
System.out.println("openFeign 下单成功!!!");
String reductedStock = stockFeignService.reductStock();
return "hi, order" + "; " + reductedStock;
}
}
启动类增加注解
- 切记启动类上得增加注解 @EnableFeignClients
package com.learning.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class);
}
}