通过上一篇文章,我们知道基于Ribbon已经能够实现服务消费,那么Feign又能起到什么作用呢?简而言之,Feign进一步简化了Ribbon 和 RestTemplate,使代码更加简洁
1.什么是Feign
Feign 是 Spring Cloud Netflix 组件中的一个轻量级 RESTful 的 HTTP 服务客户端,实现了负载均衡和 Rest 调用的开源框架,封装了 Ribbon 和 RestTemplate,实现了 WebService 的面向接口编程,进一步降低了项目的耦合度。
Feign 内置了 Ribbon,用来做客户端负载均衡调用服务注册中心的服务。
Feign 本身并不支持 Spring MVC 的注解,它有一套自己的注解,为了更方便的使用,Spring Cloud 孵化了 OpenFeign。
Feign 支持的注解和用法请参考官方文档:github.com/OpenFeign/f… 或 spring.io 官网文档
可以说,使用 Feign 实现负载均衡是首选方案。只需要你创建一个接口,然后在上面添加注解即可。
Feign 是声明式服务调用组件,其核心就是:像调用本地方法一样调用远程方法,无感知远程 HTTP 请求。
- 它解决了让开发者调用远程接口就跟调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个 HTTP 请求。无需关注与远程的交互细节,更无需关注分布式环境开发。
- 它像 Dubbo 一样,Consumer 直接调用 Provider 接口方法,而不需要通过常规的 Http Client 构造请求再解析返回数据。
2.Feign入门案例
与上文一样,我们同样在父项目下创建Feign相关的工程
引入依赖
<dependencies>
<!-- netflix eureka client 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- spring cloud openfeign 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- spring boot web 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- lombok 依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- spring boot test 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
配置文件
spring:
application:
name: feign-consumer
server:
port: 7005
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://localhost:7000/eureka/
启动类
@SpringBootApplication
@EnableFeignClients
public class FeignConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(FeignConsumerApplication.class, args);
}
}
应用实例
//指明调用的服务名称
@FeignClient("eureka-provider")
public interface ProductService {
/**
* 查询商品列表
* @return
*/
// 配置需要调用的服务地址及参数
@GetMapping("/product/list")
List<Product> selectProductList();
}
3.Feign负载均衡
Feign 封装了 Ribbon 自然也就集成了负载均衡的功能,默认采用轮询策略。修改策略的方式与之前学习 Ribbon 时讲解的配置是一致的,所以这里不再多言。
4.Feign请求传参
如何基于Feign在请求时传递参数呢?与SpringMVC类似,使用对应的注解即可
4.1 GET请求
使用 @PathVariable 注解或 @RequestParam 注解接收请求参数。
服务提供者
ProductService.java
/**
* 根据主键查询商品
*
* @param id
* @return
*/
Product selectProductById(Integer id);
ProductServiceImpl.java
/**
* 根据主键查询商品
*
* @param id
* @return
*/
@Override
public Product selectProductById(Integer id) {
return new Product(id, "冰箱", 1, 2666D);
}
ProductController.java
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
private ProductService productService;
/**
* 根据主键查询商品
*
* @param id
* @return
*/
@GetMapping("/{id}")
public Product selectProductById(@PathVariable("id") Integer id) {
return productService.selectProductById(id);
}
}
服务消费者
Productservice.java
// 声明需要调用的服务
@FeignClient("eureka-provider")
public interface ProductService {
/**
* 根据主键查询商品
*
* @return
*/
@GetMapping("/product/{id}")
Product selectProductById(@PathVariable("id") Integer id);
}
OrderServiceImpl.java
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private ProductService productService;
/**
* 根据主键查询订单
*
* @param id
* @return
*/
@Override
public Order selectOrderById(Integer id) {
return new Order(id, "003", "中国",
Arrays.asList(productService.selectProductById(5)));
}
}
4.2 POST请求
使用 @RequestBody 注解接收请求参数。
服务提供者
PoductService.java
/**
* 新增商品
*
* @param product
* @return
*/
Map<Object, Object> createProduct(Product product);
ProductServiceImpl.java
/**
* 新增商品
*
* @param product
* @return
*/
@Override
public Map<Object, Object> createProduct(Product product) {
System.out.println(product);
return new HashMap<Object, Object>() {{
put("code", 200);
put("message", "新增成功");
}};
}
ProductController.java
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
private ProductService productService;
/**
* 新增商品
*
* @param product
* @return
*/
@PostMapping("/save")
public Map<Object, Object> createProduct(@RequestBody Product product) {
return productService.createProduct(product);
}
}
服务消费者
ProductService.java
// 声明需要调用的服务
@FeignClient("eureka-provider")
public interface ProductService {
/**
* 新增商品
*
* @param user
* @return
*/
@PostMapping("/product/save")
Map<Object, Object> createProduct(Product user);
}
ProductController.java
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
private ProductService productService;
/**
* 新增商品
*
* @param product
* @return
*/
@PostMapping("/save")
public Map<Object, Object> createProduct(Product product) {
return productService.createProduct(product);
}
}
相关代码已提交至github仓库,有兴趣的朋友可以自行对比查看