目录
- 引出
- 微服务之间的调用
- 几种调用方法
- spring提供的组件
- RestTemplate的使用
- 导入依赖
- 生产者模块
- 单个配置的情况
- 多个配置的情况
- 没加.yaml的报错【报错】
- 两个同名配置【细节】
- 完整代码
- config配置
- 主启动类
- controller层
- 消费者模块
- 进行配置
- restTemplate配置类
- controller层
- 使用nacos的服务名【报错】
- 添加Ribbon负载均衡
- 改造config
- controller调用
- 总结
引出
1.微服务调用的几种方式,异步消息传递,http调用,服务网关调用,服务发现调用nacos;
2.spring提供的restTemplate,发送HTTP请求的客户端工具类;
3.nacos使用服务名报错,需要加Ribbon负载均衡;
微服务之间的调用
几种调用方法
RPC(Remote Procedure Call)远程过程调用协议,一种通过网络从远程计算机上请求服务,而不需要了解底层网络技术的协议。RPC它假定某些协议的存在,例如TPC/UDP等,为通信程序之间携带信息数据。在OSI网络七层模型中,RPC跨越了传输层和应用层,RPC使得开发,包括网络分布式多程序在内的应用程序更加容易。
微服务之间的调用可以有以下几种方式:
- 同步HTTP调用:微服务可以通过HTTP协议进行同步调用。一个微服务可以发送HTTP请求到另一个微服务的API接口,并等待响应。这种方式简单直接,适用于简单的请求和响应场景。
- 异步消息传递:微服务可以通过消息队列或消息中间件进行异步消息传递。一个微服务可以将消息发送到消息队列,另一个微服务可以从队列中接收并处理消息。这种方式可以实现解耦和异步处理,适用于高并发和异步场景。
- RPC调用:微服务可以使用远程过程调用(RPC)框架进行调用。RPC框架可以隐藏底层通信细节,使得微服务之间的调用像本地方法调用一样简单。常见的RPC框架有gRPC、Dubbo等。
- 服务网关调用:微服务可以通过服务网关进行调用。服务网关作为微服务的入口,可以对外提供统一的API接口,并将请求转发给相应的微服务。服务网关可以实现负载均衡、安全认证等功能。
- 服务发现调用:微服务可以通过服务发现机制进行调用。微服务注册到服务注册中心,其他微服务可以通过服务注册中心获取到服务的地址和端口,并进行调用。常见的服务发现工具有Consul、Eureka等。Nacos(全称为"Naming and Configuration Service")是一个开源的动态服务发现、配置管理和服务管理平台。它由阿里巴巴集团开发并开源,旨在帮助开发者更好地构建和管理微服务架构。
spring提供的组件
- RestTemplate
- Ribbon+RestTemplate
- OpenFeign
RestTemplate是Spring Framework提供的一个用于发送HTTP请求的客户端工具类。它简化了在Java应用程序中进行HTTP通信的过程,封装了底层的HTTP连接和请求/响应处理逻辑。
RestTemplate的主要特点和功能包括:
- 支持多种HTTP方法:RestTemplate支持常见的HTTP方法,如GET、POST、PUT、DELETE等,可以根据需要选择合适的方法来发送请求。
- 提供丰富的请求和响应处理方法:RestTemplate提供了多种方法来处理请求和响应,如添加请求头、设置请求参数、发送请求、获取响应等。开发者可以根据需要选择合适的方法来处理HTTP请求和响应。
- 支持请求和响应的序列化和反序列化:RestTemplate可以将请求和响应的数据进行序列化和反序列化,支持多种数据格式,如JSON、XML等。开发者可以根据需要选择合适的序列化和反序列化方式。
- 支持错误处理和异常处理:RestTemplate可以处理HTTP请求过程中的错误和异常,如连接超时、请求失败等。开发者可以根据需要进行错误处理和异常处理。
- 可扩展性和定制化:RestTemplate提供了一些扩展点和配置选项,可以进行定制化配置。开发者可以根据需要进行扩展和定制,以满足特定的业务需求。
总之,RestTemplate是一个方便易用的HTTP客户端工具类,可以在Java应用程序中发送HTTP请求并处理响应。它是Spring Framework的一部分,与Spring的其他组件集成良好,如Spring Boot、Spring Cloud等。然而,从Spring 5.0版本开始,官方推荐使用WebClient来替代RestTemplate,因为WebClient提供了更强大和灵活的功能。
Ribbon是Netflix开源的一个负载均衡器,它是Spring Cloud中的一个组件,用于在微服务架构中实现客户端的负载均衡。Ribbon可以将客户端请求均匀地分发到多个服务实例上,以提高系统的可用性和性能。
Ribbon的主要特点和功能包括:
- 客户端负载均衡:Ribbon可以根据配置的负载均衡策略,将客户端请求分发到多个服务实例上。它支持多种负载均衡算法,如轮询、随机、加权轮询等。
- 服务发现和注册:Ribbon集成了服务注册中心,可以自动发现和获取可用的服务实例。它可以与Eureka、Consul等服务注册中心进行集成。
- 故障转移和容错:Ribbon可以检测服务实例的健康状态,并在服务不可用时自动切换到其他可用的实例。它还支持熔断机制,可以在服务出现故障时进行快速失败,避免级联故障。
- 定制化配置:Ribbon提供了丰富的配置选项,可以根据需要进行定制化配置。开发者可以配置负载均衡策略、超时时间、重试次数等参数。
- 与Spring Cloud集成:Ribbon与Spring Cloud的其他组件集成良好,如Eureka、Feign等。它可以作为Feign的默认负载均衡器,实现服务间的调用和负载均衡。
总之,Ribbon是一个强大的负载均衡器,可以在微服务架构中实现客户端的负载均衡。它与Spring Cloud的其他组件紧密结合,为构建和管理微服务架构提供了重要的支持。
OpenFeign是一个声明式的Web服务客户端,它是Spring Cloud中的一个组件,用于简化和优化微服务架构中的服务间调用。OpenFeign基于Netflix的Feign库进行了扩展和增强。
OpenFeign的主要特点和功能包括:
- 声明式的API定义:通过使用注解,开发者可以定义和描述服务间的API接口,包括请求方法、路径、参数、请求头等信息。这样可以使得服务间的调用代码更加简洁和易于维护。
- 自动化的服务发现和负载均衡:OpenFeign集成了服务注册中心,可以自动发现和调用其他微服务。它还支持负载均衡,可以根据配置的负载均衡策略选择合适的服务实例进行调用。
- 内置的请求和响应拦截器:OpenFeign提供了一些内置的拦截器,可以在请求和响应的不同阶段进行拦截和处理。开发者可以自定义拦截器来实现日志记录、错误处理等功能。
- 支持多种编码器和解码器:OpenFeign支持多种编码器和解码器,可以处理不同的数据格式,如JSON、XML等。开发者可以根据需要选择合适的编码器和解码器。
- 整合了Hystrix和Ribbon:OpenFeign与Hystrix和Ribbon等其他Spring Cloud组件集成,可以实现服务的容错和熔断机制,提高系统的可靠性和稳定性。
总之,OpenFeign简化了微服务架构中的服务间调用,提供了一种简洁、声明式的方式来定义和调用服务API。它与Spring Cloud的其他组件集成良好,是构建和管理微服务架构的重要工具之一。
RestTemplate的使用
微服务之间的调用:
生产者(被使用者) —provider
消费者(应用的服务) — consumer
将两个服务注册到nacos
导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tianju</groupId>
<artifactId>springcloud-restTemplate</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>springcloud-consumer</module>
<module>springcloud-provider</module>
</modules>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.13</version>
</parent>
<!-- 依赖的管理-->
<dependencyManagement>
<dependencies>
<!--整合springcloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--整合springcloud alibaba-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.5.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 为了让别人发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 注册配置-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
生产者模块
单个配置的情况
spring:
cloud:
nacos:
discovery:
# 能够注册
register-enabled: true
server-addr: http://192.168.111.130:8848/
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
# namespace的id
namespace: 57bca93f-1161-4649-aec3-da79c3aa7cc2
# # 配置单个
group: DEV
name: book-cofig
file-extension: yaml
application:
name: springCloud-provider
多个配置的情况
没加.yaml的报错【报错】
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘providerController’: Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder ‘book.name’ in value “${book.name}”
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder ‘book.name’ in value “${book.name}”
两个同名配置【细节】
完整代码
config配置
bootstrap.yml
spring:
cloud:
nacos:
discovery:
# 能够注册
register-enabled: true
server-addr: http://192.168.111.130:8848/
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
# namespace的id
namespace: 57bca93f-1161-4649-aec3-da79c3aa7cc2
# # 配置单个
# group: DEV
# name: book-cofig
# file-extension: yaml
# 配置多个 TODO:配置多个的时候,要加上.yaml后缀,nacos中的命名也要加.yaml
# TODO:如果两个配置里面的值相同,则后面加载进来的会覆盖前面的;
extension-configs:
# - data-id: book-cofig
# group: DEV
# refresh: true
- data-id: book-config1.yaml
group: DEV
refresh: true
- data-id: book-config2.yaml
group: DEV
refresh: true
application:
name: springCloud-provider
application.yml
server:
port: 9099
主启动类
package com.tianju.cloud.provider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class, args);
}
}
controller层
package com.tianju.cloud.provider.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/provider")
public class ProviderController {
@Value("${book.name}")
private String movieName;
@Value("${spring.application.name}")
private String serverId;
@Value("${server.port}")
private int port;
@GetMapping("/hello")
public String hello(){
String s = "服务"+serverId+",端口:"+port+",电影名:"+movieName;
System.out.println(s);
return s;
}
}
消费者模块
进行配置
spring:
cloud:
nacos:
discovery:
# 能够注册
register-enabled: true
server-addr: http://192.168.111.130:8848/
application:
name: springCloud-consumer
restTemplate配置类
package com.tianju.consumer.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean(name = "restTemplateA") // 定义名称
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
controller层
package com.tianju.consumer.controller;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
@RequestMapping("/api/consumer")
public class ConsumerController {
@Resource // 根据名称注入
private RestTemplate restTemplateA;
@GetMapping("/nihao")
public String nihao(){
String url = "http://localhost:9099/api/provider/hello";
ResponseEntity<String> forEntity = restTemplateA
.getForEntity(
url,
String.class
);
String body = forEntity.getBody();
System.out.println("消费者获取生产者提供的数据"+body);
return body;
}
}
使用nacos的服务名【报错】
添加Ribbon负载均衡
<!--客户端负载均衡loadbalancer-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
改造config
package com.tianju.consumer.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean(name = "restTemplateA") // 定义名称
public RestTemplate restTemplate(){
return new RestTemplate();
}
@LoadBalanced // 具有软件负载均衡能力
@Bean(name = "restTemplateWith") // 定义名称
public RestTemplate restTemplateWith(){
return new RestTemplate();
}
}
controller调用
package com.tianju.consumer.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
@RequestMapping("/api/consumer")
public class ConsumerController {
@Resource // 根据名称注入
private RestTemplate restTemplateA;
@GetMapping("/nihao")
public String nihao(){
String url = "http://localhost:9099/api/provider/hello";
ResponseEntity<String> forEntity = restTemplateA
.getForEntity(
url,
String.class
);
String body = forEntity.getBody();
System.out.println("消费者获取生产者提供的数据"+body);
return body;
}
@Resource
private RestTemplate restTemplateWith;
@GetMapping("/nihaox")
public String nihaoX(){
String url = "http://springCloud-provider/api/provider/hello";
ResponseEntity<String> forEntity = restTemplateWith.getForEntity(url, String.class);
String body = forEntity.getBody();
System.out.println("消费者获取生产者提供的数据"+body);
return body;
}
}
总结
1.微服务调用的几种方式,异步消息传递,http调用,服务网关调用,服务发现调用nacos;
2.spring提供的restTemplate,发送HTTP请求的客户端工具类;
3.nacos使用服务名报错,需要加Ribbon负载均衡;