Author:海梅鱼
PublishDate:2023.08.15
原文链接
摘要
在微服务架构中,服务的注册与发现是至关重要的,它允许不同的服务相互通信,提供弹性、可伸缩的架构。Spring Cloud Alibaba与Nacos的结合为服务注册与发现提供了强大的支持。
1. 什么是Nacos
Nacos(Naming and Configuration Service)是一个用于发现、配置和管理微服务的开源平台。它提供了一系列简单易用的功能,包括动态服务发现、服务配置、服务元数据管理和流量管理。作为Spring Cloud Alibaba中的重要组件,Nacos类似于Consul和Eureka,同时它还具备分布式配置中心的功能,支持热加载配置。
2. 作用
Nacos的主要作用包括:
- 服务发现与健康监测:Nacos可以帮助微服务在集群中进行动态的注册和发现,以及对服务的健康状态进行监测。
- 动态配置服务:Nacos可以作为配置中心,支持在运行时动态调整配置,提供管理界面,并支持多种配置维度。
- 动态DNS服务:Nacos支持基于服务名称的动态DNS解析,可以方便地实现服务之间的通信。
- 服务及其元数据管理:Nacos提供服务的元数据管理功能,使得服务的管理更加便捷。
3. 下载与安装
安装Nacos前需要保证已安装Java环境。Nacos的安装步骤如下:
-
从官网下载Nacos的稳定版本解压包,下载地址:https://github.com/alibaba/nacos/releases 。(提醒:github下载速度太慢,可以选择下载源码自行编译)
-
编译/下载完成后,解压下载的包,在解压后的文件夹中的/bin目录中,使用以下命令启动Nacos:
在Linux系统下:
sh startup.sh -m standalone
在Windows系统下:
startup.cmd -m standalone
-
启动成功后,访问http://localhost:8848/nacos 在浏览器中进入Nacos的管理界面。默认的登录用户名和密码均为nacos。
4. 服务注册和发现
服务注册与发现是微服务治理的核心,Nacos作为服务注册与发现组件,与Eureka和Consul等组件类似。以下为构建两个微服务的示例:
服务注册
将两个服务注册到Nacos
环境:
- Spring Boot:2.4.4
- Spring Cloud:2020.0.2
- Spring Cloud Alibaba:2020.0.RC1
- 构建父工程
你可以参考我的pom进行构建
...pom
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>SpringCloudStudy</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringCloudStudy</name>
<description>SpringCloudStudy</description>
<packaging>pom</packaging>
<modules>
<module>provider</module>
<module>consumer</module>
</modules>
<properties>
<java.version>1.8</java.version>
<spring-boot.version>2.4.4</spring-boot.version>
<spring-cloud.version>2020.0.2</spring-cloud.version>
<spring-cloud-alibaba.version>2020.0.RC1</spring-cloud-alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- spring boot 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring cloud 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring cloud alibaba 依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
- 构建provider微服务
- pom配置
新建一个SpringBoot项目,引入Nacos和Web依赖。
<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>
</dependencies>
- yaml配置:
程序的启动端口为8762,应用名为provider,向nacos server注册的地址为127.0.0.1:8848。
server:
port: 8762
spring:
application:
name: provider
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
- 在启动类上加入@EnableDiscoveryClient注解,并编写一个服务接口
@SpringBootApplication
@RestController
@EnableDiscoveryClient
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
@Value("${server.port}")
String port;
@GetMapping("/hi")
public String hi(@RequestParam(value = "name", defaultValue = "forezp",required = false) String name) {
return "hello " + name + ", i'm provider ,my port:" + port;
}
}
- 构建consumer服务(与provider服务类似)
- pom配置
创建一个Spring Boot项目,引入Nacos、Web、Feign和LoadBalancer依赖。
<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>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
- yaml配置
在配置文件中配置Nacos的注册中心地址。
server:
port: 8763
spring:
application:
name: consumer
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
- 主程序类
在启动类上加入@EnableDiscoveryClient和@EnableFeignClients注解。
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients // feign服务调用,服务调用部分代码请看下面
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
至此,测试工程搭建完成,启动两个服务后可以在nacos控制台服务列表
查看注册的服务
5. 服务调用
Nacos作为服务注册与发现的组件,使用Feign和RestTemplate进行服务调用的方式与Eureka和Consul无差异。Feign是一个声明式的HTTP客户端,使得远程调用更加便捷。RestTemplate则结合了Ribbon实现了负载均衡功能,也可以用于服务调用。
- 使用Feign进行服务调用
下面代码演示了如何在Spring Cloud应用中使用Feign框架来实现服务消费者与服务提供者之间的通信。Feign是一个声明式的HTTP客户端,它简化了微服务之间的远程调用,使得开发者可以通过编写接口的方式来定义服务的调用,而不必显式地编写HTTP请求和参数转换的代码。
// 引入下面两个依赖
<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>
// consumer使用feign调用服务
// ConsumerControll
@RestController
public class ConsumerController {
@Autowired
ProviderClient providerClient;
@GetMapping("/hi-feign")
public String hiFeign(){
return providerClient.hi("feign");
}
}
// feignclient 接口
@FeignClient(value = "provider" )
public interface ProviderClient {
@GetMapping("/hi")
String hi(@RequestParam(value = "name", defaultValue = "forezp", required = false) String name);
}
测试结果:
- 使用RestTemplate进行调用服务
下面的代码展示了在Spring Cloud应用中RestTemplate如何使用Ribbon作为负载均衡组件来调用其他微服务提供的接口
// 1. 引入依赖ribbon作为负载均衡组件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
// 2. 注入resttemplate
@LoadBalanced // 加上@LoadBalanced注解即可在RestTemplate上开启LoadBalanced负载均衡的功能。
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
// 3. 在Controller中定义接口
@Autowired
RestTemplate restTemplate;
@GetMapping("/hi-resttemplate")
public String hiResttemplate(){
return restTemplate.getForObject("http://provider/hi?name=resttemplate",String.class);
}
测试结果:
6. 注意事项与避坑
在使用Nacos时,需要注意版本兼容性问题,确保引入的Spring Boot和Spring Cloud版本与Nacos版本兼容。避免因版本不一致而导致的启动异常。同时,需要正确配置Nacos的注册中心地址,确保微服务能够正确注册和发现。下面是版本兼容问题可能引起的报错:
org.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery:jar:2.2.3.RELEASE was not found in http://maven.aliyun.com/nexus/content/groups/public during a previous attempt
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata