Feign
大约 3 分钟
What's Feign?
相关信息
一个微服务间用于远程服务调用的组件。feign 默认集成了 ribbon 做负载均衡,使用 RPC 方式进行远程方法调用。
RPC
RPC 是一个网络通信协议,与 HTTP 的不同在于数据包更小,更适合服务间的内部调用。
Java 中的 HttpClient
就是 RPC 调用。
服务提供者 & 消费者
服务提供者:一次业务中,被其他微服务调用的服务。(提供接口给其他微服务)
服务消费者:一次业务中,调用其他微服务的服务。(调用其他微服务提供的接口)
一个微服务既可以是提供者又可以是消费者。
远程调用的问题
- 消费者该如何获取服务提供者的地址信息?(地址可能会随着环境变化)
- 如果有多个服务提供者,消费者该如何选择?(服务提供者为一个集群)
- 消费者如何得知服务提供者的健康状态?
使用Feign
- 导入依赖。
- 声明一个接口充当被调用的服务提供方。
- 在消费者的启动类上添加注解 @EnableFeignClients("com.ly.api") 指定接口所有位置,将自动使用代理的方式生成接口的实现类并放入 IOC 容器中。
- 被调用的服务,控制层方法的参数使用 @RequestBody 或 @RequestParam 注解与传入参数进行绑定,方法必须返回 json 格式数据。
- 配置 ribbon 实现服务间调用的负载均衡。
- 设置 ribbon 超时时间。
<!-- feign相关依赖,通过该模块的功能实现服务间的调用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
package com.ly.api;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Map;
// 声明这个接口代表的是 stocks-server 的客户端
@FeignClient("stocks-server")
public interface StocksAPI {
// 方法的签名必须和对应服务的接口一致
// 在方法上指定对应接口的请求全路径
@RequestMapping("/stocks/queryStocksNumberByGoodsId")
// 所有参数使用 @RequestParam 注解,尤其是多个参数的方法
public Map<String,Object> queryStocksNumberByGoodsId(@RequestParam("goodsId") Integer goodsId);
@RequestMapping("/stocks/subStocksNumber")
public Map<String,Object> subStocksNumber(@RequestParam("goodsId") Integer goodsId);
@RequestMapping("/points/addPoints")
// @RequestBody 绑定对象类型参数
public Map<String,Object> addPoints(@RequestBody Points points);
}
import com.ly.service.StocksService;
import com.netflix.discovery.converters.Auto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;
@Controller
@RequestMapping("/stocks")
public class StocksController {
@Autowired
private StocksService stocksService;
/*
* 服务提供方的接口返回 json 格式数据
* 服务提供方的接口方法的参数使用 @RequestParam() 绑定
* */
@RequestMapping("/queryStocksNumberByGoodsId")
@ResponseBody
public Map<String,Object> queryStocksNumberByGoodsId(@RequestParam("goodsId") int goodsId){
int number = stocksService.queryStocksNumberByGoodsId(goodsId);
Map<String,Object> result = new HashMap<>();
result.put("number",number);
// 返回执行该方法的http状态码
result.put("code",200);
result.put("message","ok");
System.out.println("方法被调用");
return result;
}
}
point-service:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
# RoundRobinRule 轮询(默认)
# RandomRule 随机
# AvailabilityFilteringRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态 的服务,还有并发的连接数超过阈值的服务,然后对剩余的服务列表进行 轮询
# WeightedResponseTimeRule 权重 根据平均响应时间计算所有服务的权重,响 应时间越快服务权重越大被选中的概率越高。刚启动时,如果统计信息不 足,则使用轮询策略,等信息足够,切换到 WeightedResponseTimeRule
# RetryRule 重试 先按照轮询策略获取服务,如果获取失败则在指定时间内重 试,获取可用服务
# BestAvailableRule 选过滤掉多次访问故障而处于断路器跳闸状态的服务,然后 选择一个ZoneAvoidanceRule 符合判断server所在区域的性能和server的 可用性选择服务
# 策略选择:
# 1、如果每个机器配置一样,则建议不修改策略 (推荐)
# 2、如果部分机器配置强,则可以改为 WeightedResponseTimeRule
# 防止 ribbon 超时
ribbon:
# 改为4秒
ReadTimeout: 4000
ConnectTimeout: 4000