目录
1 直接使用RestTemplate发起Http请求
1.1 将RestTemplate注册为SpringBean
1.2 在service实现类中注入RestTemplate
1.3 使用注入的RestTemplate 传入参数后发起http请求
2 引入Nacos后使用RestTemplate发起Http请求
2.1 基础知识
2.2 Nacos的使用
2.2.1 引入nacos discovery依赖(单个project一般在父工程的pom中引入)
2.2.2 在服务中的配置文件application.yaml 中配置Nacos地址。
2.2.3 启动服务即可被注册中心扫描到,(同一个服务多个实例也会被扫描到)
2.3 在Nacos基础上通过RestTemplate发起Http请求
3 基于OpenFeign发起远程请求
3.1 OpenFeign 准备工作
3.1.1 引入依赖
3.1.2 向启动类中加上@EnableFeignClients注解,启动OpenFeign功能,第三个注解
3.2 编写FeignClient
3.2.1 创建对应的Client类,如ItemClient类,用来处理对应的请求,如下示例就是处理根据ids查询商品的请求
3.2.2 之前service的实现类中的代码变更如下
4 OpenFeign拓展
单体架构变为微服务架构需要解决的问题之一就是各个微服务间的通信问题,解决方法就是发送http请求,过程如下示例图
若对其他基础知识不感兴趣请转3 基于OpenFeign发起远程请求
1 直接使用RestTemplate发起Http请求
不引入其他依赖,直接使用RestTemplate发起Http请求实现远程调用的方法(不推荐,只适合微服务单一实体情况)
1.1 将RestTemplate注册为SpringBean
在启动类中加入以下代码
@SpringBootApplication
public class CartApplication {
public static void main(String[] args) {
SpringApplication.run(CartApplication.class, args);
}
//加入下面的代码
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
1.2 在service实现类中注入RestTemplate
如下图
1.3 使用注入的RestTemplate 传入参数后发起http请求
下面是一个远程调用的方法获取购物车商品数据的示例方法:
private void handleCartItems(List<CartVO> vos) {
// 1.获取商品id
Set<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());
// 2利用RestTemplate
ResponseEntity<List<ItemDTO>> response = restTemplate.exchange(
"http://localhost:8081/items?ids={ids}", //http请求路径,
HttpMethod.GET, //请求类型,GET,PUT,POST,DELETE
null, //请求实体
new ParameterizedTypeReference<List<ItemDTO>>() {
}, //返回数据的类型,此处通过new 一个对象传入结果类型
Map.of("ids", CollUtil.join(itemIds, ",")) //讲数据拼接到请求路径中
);
if(!response.getStatusCode().is2xxSuccessful()){
return; //判断相应状态码,不成功直接结束
}
List<ItemDTO> items = response.getBody(); //没有结束则表示请求成功,获得响应数据
// ..... 其他后续操作
}
以上便是直接使用RestTemplate的过程,缺点在于若一个微服务有多个实例,或多个微服务时,无法快速做出合适的选择,不适合多变的情况。为解决这种情况,则引入注册中心Nacos。
2 引入Nacos后使用RestTemplate发起Http请求
在以上情况的基础下,引入注册中心(此处引用Nacos),实现多个服务,多个实例间的管理。
2.1 基础知识
服务治理中的三个角色分别是什么?
- 服务提供者:暴露服务接口,供其它服务调用
- 服务消费者:调用其它服务提供的接口
- 注册中心:记录并监控微服务各实例状态,推送服务变更信息
消费者如何知道提供者的地址?
- 服务提供者会在启动时注册自己信息到注册中心,消费者可以从注册中心订阅和拉取服务信息
消费者如何得知服务状态变更?
- 服务提供者通过心跳机制向注册中心报告自己的健康状态,当心跳异常时注册中心会将异常服务剔除,并通知订阅了该服务的消费者
当提供者有多个实例时,消费者该选择哪一个?
- 消费者可以通过负载均衡算法,从多个实例中选择一个
2.2 Nacos的使用
首先需要安装注册中心Nacos,请根据自己的平台进行安装(docker或者本机)安装以后注意ip,此处省略安装过程。
通过 (服务器ip:8848/nacos) 访问或者 (localhost:8848/nacos) 访问。默认账号密码都是nacos
安装以后的使用步骤
2.2.1 引入nacos discovery依赖(单个project一般在父工程的pom中引入)
<!--nacos 服务注册发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2.2.2 在服务中的配置文件application.yaml 中配置Nacos地址。
如商品服务item-service为例:
spring:
application:
name: item-service #微服务名称
cloud:
nacos:
server-addr: 172.16.121.128:8848 #nacos的地址
2.2.3 启动服务即可被注册中心扫描到,(同一个服务多个实例也会被扫描到)
2.3 在Nacos基础上通过RestTemplate发起Http请求
现在注册中心配置完以后,若想发起远程调用,过程如下
- 根据微服务名称获得实例列表
- 负载均衡,选择其中一个实例
- 获取uri,
- RestTemplate发起请求
之前的代码变更如下
// private final RestTemplate restTemplate;
// private final DiscoveryClient discoveryClient;
//别忘了在实现类中引入上面两个Bean
private void handleCartItems(List<CartVO> vos) {
// 1.获取商品id
Set<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());
// 2 整个过程
// 2.1根据服务名称获取实例列表
List<ServiceInstance> instances = discoveryClient.getInstances("item-service");
if (CollUtils.isEmpty(instances)){
return; //确保通过微服务名称获取到实例,实例列表不为空
}
// 2.2手写负载均衡 获得实例
ServiceInstance serviceInstance = instances.get(RandomUtil.randomInt(instances.size())); //负载均衡算法获取其中一个实例
// 2.3 获取uri
URI uri = serviceInstance.getUri();
// 2.4 利用RestTemplate发起请求
ResponseEntity<List<ItemDTO>> response = restTemplate.exchange(
uri+"/items?ids={ids}", //http请求路径,
HttpMethod.GET, //请求类型,GET,PUT,POST,DELETE
null, //请求实体
new ParameterizedTypeReference<List<ItemDTO>>() {
}, //返回数据的类型,此处通过new 一个对象传入结果类型
Map.of("ids", CollUtil.join(itemIds, ",")) //讲数据拼接到请求路径中
);
if(!response.getStatusCode().is2xxSuccessful()){
return; //判断相应状态码,不成功直接结束
}
List<ItemDTO> items = response.getBody(); //没有结束则表示请求成功,获得响应数据
// ..... 其他后续操作
}
到这里会有人发问,为什么引入Nacos还麻烦了?!
是的多了两步,通过名称找到实例列表,然后选取实例,然后发送请求。是麻烦了一点,但是解决了普通RestTemplate能向单一实例发送请求的问题, 引入Nacos可以通过负载均衡向多实例发起请求。
但是很显然这么麻烦并不符合开发需求,因此引入OpenFeign。
3 基于OpenFeign发起远程请求
OpenFeign是一个声明式的http客户端,是SpringCloud在Eureka公司开源的Feign基础上改造而来,是为了简化微服务间远程请求。
3.1 OpenFeign 准备工作
3.1.1 引入依赖
一般将依赖引入单独的api module下,若不理解这个单独的module,可看下一篇拓展文章
<!--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>
3.1.2 向启动类中加上@EnableFeignClients注解,启动OpenFeign功能,第三个注解
@MapperScan("com.hmall.cart.mapper")
@SpringBootApplication
@EnableFeignClients(basePackages = "com.hmall.api.client")
public class CartApplication {
public static void main(String[] args) {
SpringApplication.run(CartApplication.class, args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
3.2 编写FeignClient
准备工作完成以后,就可以编写FeignClient了,如下图,之前购物车服务需要通过RestTemplate向商品服务发起请求,现在编写ItemClient 商品Feign客户端,来处理此请求,不再需要RestTemplate了。
3.2.1 创建对应的Client类,如ItemClient类,用来处理对应的请求,如下示例就是处理根据ids查询商品的请求
3.2.2 之前service的实现类中的代码变更如下
请求购物车商品的复杂代码变的很简单
//不再需要注入其他Bean 直接注入ItemClient
//直接注入微服务对应的Client Bean !!!
private final ItemClient itemClient;
//注入Bean 不再需要RestTemplate和DiscoveryClient了,只需要上面的itemClient即可
private void handleCartItems(List<CartVO> vos) {
// 1.获取商品id
Set<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());
// 2. 直接调用Client 中的方法即可发起请求
List<ItemDTO> items = itemClient.queryItemByIds(itemIds);//直接调用方法获得数据
if (CollUtils.isEmpty(items)) {
return; //判断数据是否为空 空则直接结束
}
//...后续其他操作
}
通过以上你便可掌握微服务间通过OpenFeign快速简单的发起请求获得数据。简单很多,不再需要自己选择实例,不用自己做负载均衡,简单便捷。
4 OpenFeign拓展
OpenFeign 拓展讲解https://blog.csdn.net/weixin_49418695/article/details/139549013?spm=1001.2014.3001.5501