本篇博客将通过实例演示如何在 Spring Cloud 中使用 Nacos 实现服务注册与发现,并使用 OpenFeign 进行服务间调用。你将学到如何搭建一个完整的微服务通信框架,帮助你快速开发可扩展、高效的分布式系统。
目录
前言
服务注册和发现
服务注册
编辑 服务发现
OpenFeign
快速入门
总结
前言
本篇博客将通过实例演示如何在 Spring Cloud 中使用 Nacos 实现服务注册与发现,并使用 OpenFeign 进行服务间调用。你将学到如何搭建一个完整的微服务通信框架,帮助你快速开发可扩展、高效的分布式系统。
服务注册和发现
服务注册
服务注册步骤如下:
(1)引入nacos discovery依赖
<!--nacos 服务注册发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
(2)配置Nacos地址
spring:
application:
name:item-service#服务名称
cloud:
nacos:
server-addr:虚拟机地址:8848#nacos地址(我的nacos部署在虚拟机里面)
在item-service模块中添加依赖
在item-service的application.yaml配置nacos地址
为多个服务测试,需要再配置一个item-service实例
配置启动项,需重命名和配置端口号
访问nacos的服务管理,就可以发现注册成功呢
服务发现
消费者需要连接nacos以拉取和订阅服务,因此服务发现的前两步与服务注册是一样,后面再加上服务调用即可:
(1) 引入nacos discovery依赖
...
(2)配置nacos地址
...
(3)服务发现
private final DiscoveryClient discoveryclient;
private void handleCartItems(List<CartV0>vos){
//1.根据服务名称,拉取服务的实例列表List<ServiceInstance>instances =
discoveryclient.getInstances("item-service");
//2.负载均衡,挑选一个实例
ServiceInstance instance = instances.get(RandomUtil.randomInt(instances.size()));
//3.获取实例的TP和端口
URI uri = instance.getUri();
略...
}
将nacos依赖导入cart-service模块
在cart-service的application.yaml文件中配置nacos地址
修改购物车模块中的查询商品信息功能
package com.hmall.cart.service.impl;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.cart.domain.dto.CartFormDTO;
import com.hmall.cart.domain.dto.ItemDTO;
import com.hmall.cart.domain.po.Cart;
import com.hmall.cart.domain.vo.CartVO;
import com.hmall.cart.mapper.CartMapper;
import com.hmall.cart.service.ICartService;
import com.hmall.common.exception.BizIllegalException;
import com.hmall.common.utils.BeanUtils;
import com.hmall.common.utils.CollUtils;
import com.hmall.common.utils.UserContext;
import lombok.RequiredArgsConstructor;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* <p>
* 订单详情表 服务实现类
* </p>
*
*/
@Service
@RequiredArgsConstructor
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {
private final RestTemplate restTemplate;
private final DiscoveryClient discoveryClient;
private void handleCartItems(List<CartVO> vos) {
// 1.获取商品id
Set<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());
// 2.查询商品
//根据服务名称获取服务的实例列表
List<ServiceInstance> instances = discoveryClient.getInstances("item-service");
if(CollUtils.isEmpty(instances)){
return;
}
//手写负载均衡
ServiceInstance instance = instances.get(RandomUtil.randomInt(instances.size()));
//利用restTemolate发起http请求,得到http的响应
ResponseEntity<List<ItemDTO>> response = restTemplate.exchange(
instance.getUri()+"/items?ids={ids}",
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<ItemDTO>>() {
},
Map.of("ids", CollUtils.join(itemIds, ","))
);
//解析响应
if(!response.getStatusCode().is2xxSuccessful()){
//查询失败直接结束
return;
}
List<ItemDTO> items = response.getBody();
if (CollUtils.isEmpty(items)) {
return;
}
// 3.转为 id 到 item的map
Map<Long, ItemDTO> itemMap = items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));
// 4.写入vo
for (CartVO v : vos) {
ItemDTO item = itemMap.get(v.getItemId());
if (item == null) {
continue;
}
v.setNewPrice(item.getPrice());
v.setStatus(item.getStatus());
v.setStock(item.getStock());
}
}
...
}
OpenFeign
快速入门
利用Nacos现了服务的治理,利用RestTemplate实现了服务的远程调用。但是远程调用的代码太复杂了,我们可以通过OpenFeign组件来让操作更加简单。
OpenFeign是一个声明式的http客户端,是SpringCloud在Eureka公司开源的Feign基础上改造而来。官方地址:https://github.com/openFeign/feign
其作用就是基于SpringMVC的常见注解,帮我们优雅的实现http请求的发送。
OpenFeign已经被SpringCloud自动装配,实现起来非常简单:
(1)引入依赖,包括OpenFeign和负载均衡组件SpringCloudLoadBalancer
<!--OpenFeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--负载均衡-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
(2)通过@EnableFeignClients注解,启用OpenFeign功能
@EnableFeignclients
@SpringBootApplication
public class cartApplication{//...略}
OpenFeign已经被SpringCloud自动装配,实现起来非常简单:
(3)编写FeignClient
@FeignClient(value =item-service")
public interface Itemclient{
@GetMapping("/items")
List<ItemDT0>queryItemByIds(@RequestParam("ids")Collection<Long> ids);
}
(4)使用FeignClient,实现远程调用
List<ItemDTO>items =itemclient.queryItemByIds(List.of(1,2,3));
在cart-service模块的pom.xml文件中导入依赖
在CartApplication启动类上加@EnableFeignClients注解开启OpenFeign
编写ItemClient接口
package com.hmall.cart.client;
import com.hmall.cart.domain.dto.ItemDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@FeignClient("item-service")
public interface ItemClient {
@GetMapping("/items")
List<ItemDTO> queryItemsByIds(@RequestParam("id") Collection<Long> ids);
}
修改购物车中的查询物品信息功能
@Service
@RequiredArgsConstructor
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {
private final ItemClient itemClient;
private void handleCartItems(List<CartVO> vos) {
// 1.获取商品id
Set<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());
// 2.查询商品
Client.queryItemsByIds(itemIds);
if (CollUtils.isEmpty(items)) {
return;
}
// 3.转为 id 到 item的map
Map<Long, ItemDTO> itemMap = items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));
// 4.写入vo
for (CartVO v : vos) {
ItemDTO item = itemMap.get(v.getItemId());
if (item == null) {
continue;
}
v.setNewPrice(item.getPrice());
v.setStatus(item.getStatus());
v.setStock(item.getStock());
}
}
总结
通过本篇博客的学习,我们了解了如何利用 Nacos 完成服务的注册与发现,让微服务之间可以轻松互相找到彼此并进行通信。我们还探索了如何通过 OpenFeign 简化服务间的调用,使得服务之间的交互更加便捷高效。
总结一下,本篇博客的关键点:
- 服务注册与发现:通过 Nacos,服务可以在启动时向 Nacos 注册自己,其他服务可以通过 Nacos 查询并发现目标服务。
- 服务调用:借助 OpenFeign,我们可以通过接口声明的方式来调用其他服务,而不需要直接编写 HTTP 请求,极大地提高了开发效率。
- 分布式架构:通过结合 Nacos 和 OpenFeign,我们能够更加高效地构建微服务架构,实现松耦合、灵活的服务间通信。