/**
-
调用根据商品ID获取库存量接口
-
@param goodsId
-
@return
*/
@GetMapping(value = “/shop-stock/api/account/get”)
Integer getAccountById(@RequestParam(value = “goodsId”) Integer goodsId);
}
- 定义完成之后,我们还要在启动类上加上注解
@EnableFeignClients
去扫描Feign客户端。
@SpringBootApplication
@MapperScan(“cn.fighter3.mapper”)
@EnableDiscoveryClient
@EnableFeignClients(basePackages = “cn.fighter3.client”)
public class EshopGoodsApplication {
public static void main(String[] args) {
SpringApplication.run(EshopGoodsApplication.class, args);
}
}
使用Feign客户端也很简单,直接在需要使用的地方注入就行了。
@Autowired
private StockClientFeign stockClientFeign;
- 商品服务控制层
/**
-
-
前端控制器
-
@author 三分恶
-
@since 2021-05-18
*/
@RestController
@RequestMapping(“/shop-goods”)
@Api(value = “商品管理接口”, tags = “商品接口”)
@Slf4j
public class ShopGoodsController {
@Autowired
private IShopGoodsService goodsService;
@PostMapping(value = “/add”)
@ApiOperation(value = “添加商品”)
public CommonResult addGoods(@RequestBody GoodsAddDTO goodsAddDTO) {
return this.goodsService.addGoods(goodsAddDTO);
}
@GetMapping(value = “/get/by-id”)
@ApiOperation(value = “根据ID获取商品”)
public CommonResult getGoodsById(@RequestParam Integer goodsId) {
return this.goodsService.getGoodsById(goodsId);
}
}
- 服务层
在服务层除了对商品库的操作之外,还通过Feign客户端远程调用库存服务的接口。
@Service
@Slf4j
public class ShopGoodsServiceImpl extends ServiceImpl<ShopGoodsMapper, ShopGoods> implements IShopGoodsService {
@Autowired
private StockClientFeign stockClientFeign;
/**
-
添加商品
-
@param goodsAddDTO
-
@return
*/
public CommonResult addGoods(GoodsAddDTO goodsAddDTO) {
ShopGoods shopGoods = new ShopGoods();
BeanUtils.copyProperties(goodsAddDTO, shopGoods);
this.baseMapper.insert(shopGoods);
log.info(“添加商品,商品主键:{}”, shopGoods.getGoodsId());
log.info(shopGoods.toString());
StockAddDTO stockAddDTO = StockAddDTO.builder().goodsId(shopGoods.getGoodsId()).account(goodsAddDTO.getAccount()).build();
log.info(“准备添加库存,参数:{}”, stockAddDTO.toString());
Integer stockId = this.stockClientFeign.addStock(stockAddDTO);
log.info(“添加库存结束,库存主键:{}”, stockId);
return CommonResult.ok();
}
/**
-
获取商品
-
@param goodsId
-
@return
*/
public CommonResult getGoodsById(Integer goodsId) {
GoodsVO goodsVO = new GoodsVO();
//获取商品基本信息
ShopGoods shopGoods = this.baseMapper.selectById(goodsId);
BeanUtils.copyProperties(shopGoods, goodsVO);
//获取商品库存数量
Integer account = this.stockClientFeign.getAccountById(goodsId);
log.info(“商品数量:{}”, account);
goodsVO.setAccount(account);
return CommonResult.ok(goodsVO);
}
}
- 实体类
添加库存实体类和库存服务相同,略过,商品展示实体类
@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value = “商品”, description = “”)
public class GoodsVO implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = “商品主键”)
private Integer goodsId;
@ApiModelProperty(value = “商品名称”)
private String goodsName;
@ApiModelProperty(value = “价格”)
private BigDecimal price;
@ApiModelProperty(value = “商品介绍”)
private String description;
@ApiModelProperty(value = “数量”)
private Integer account;
}
2.2.3、效果演示
接下来启动nacos-server,商品服务,库存服务。
访问地址 http://127.0.0.1:8848/nacos/index.html ,登录之后,可以在服务列表里看到我们注册的两个服务:
访问商品服务Knife4j地址:http://localhost:8020/doc.html ,可以看到添加商品和根据商品ID查找商品的接口,分别调试调用:
- 添加商品
- 根据ID获取商品
可以看到各自对应的数据库也有数据生成:
整体的远程调用示意图大概如下:
关于负载均衡,这里偷个懒,就不再演示了。
感兴趣的可以吧库存服务打包,以不同的端口启动,然后添加商品,通过日志查看商品服务调用的负载情况。
Feign负载均衡是通过Ribbon实现,Ribbon是一种客户端的负载均衡——也就是从注册中心获取服务列表,由客户端自己决定调用哪一个远程服务。
Ribbon的主要负载均衡策略有以下几种:
| 规则名称 | 特点 |
| :-: | :-: |
| AvailabilityFilteringRule | 过滤掉一直连接失败的被标记为circuit tripped的后端Server,并 过滤掉那些高并发的后端Server或者使用一个AvailabilityPredicate 来包含过滤server的逻辑,其实就是检查status里记录的各个server 的运行状态 |
| BestAvailableRule | 选择一个最小的并发请求的server,逐个考察server, 如果Server被tripped了,则跳过 |
| RandomRule | 随机选择一个Server |
| ResponseTimeWeightedRule | 已废弃,作用同WeightedResponseTimeRule |
| WeightedResponseTimeRule | 根据响应时间加权,响应时间越长,权重越小,被选中的可能性越低 |
| RetryRule | 对选定的负载均衡策略加上重试机制,在一个配置时间段内当 选择Server不成功,则一直尝试使用subRule的方式选择一个 可用的Server |
| RoundRobinRule | 轮询选择,轮询index,选择index对应位置的Server |
| ZoneAvoidanceRule | 默认的负载均衡策略,即复合判断Server所在区域的性能和Server的可用性 选择Server,在没有区域的环境下,类似于轮询(RandomRule) |
这里就不再展开讲了,感兴趣的自行了解。
========================================================================
- 发现远程调用的时候出现读取响应结果超时的情况:
java.net.SocketTimeoutException: Read timed out
修改Ribbon超时配置就行了:
ribbon超时时间
ribbon:
ReadTimeout: 30000
ConnectTimeout: 30000
- Feign接口中,使用
@RequestParam
报错
发现报错:
Caused by: java.lang.IllegalStateException: RequestParam.value() was empty on parameter 0
Feign声明里需要加上value
:
Integer getAccountById(@RequestParam(value = “goodsId”) Integer goodsId);
“简单的事情重复做,重复的事情认真做,认真的事情有创造性地做!”——
我是三分恶,可以叫我老三/三分/三哥/三子,一个能文能武的全栈开发,咱们下期见!
参考:
【1】:小专栏《SpringCloudAlibaba微服务实战 》
【2】:SpringCloud Alibaba微服务实战三 - 服务调用
【3】:Ribbon的负载均衡策略、原理和扩展
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
最后
Java架构学习技术内容包含有:Spring,Dubbo,MyBatis, RPC, 源码分析,高并发、高性能、分布式,性能优化,微服务 高级架构开发等等。
还有Java核心知识点+全套架构师学习资料和视频+一线大厂面试宝典+面试简历模板可以领取+阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题+Spring源码合集+Java架构实战电子书+2021年最新大厂面试题。
1994722558)]
[外链图片转存中…(img-wG64jHMT-1711994722559)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-P9iWIWK9-1711994722559)]
最后
Java架构学习技术内容包含有:Spring,Dubbo,MyBatis, RPC, 源码分析,高并发、高性能、分布式,性能优化,微服务 高级架构开发等等。
还有Java核心知识点+全套架构师学习资料和视频+一线大厂面试宝典+面试简历模板可以领取+阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题+Spring源码合集+Java架构实战电子书+2021年最新大厂面试题。
[外链图片转存中…(img-crfb3Fi7-1711994722559)]