一文秒懂SpringCloud Alibaba中的服务组件——Nacos

Java技术迷

共 9990字,需浏览 20分钟

 ·

2021-05-14 20:31


汪伟俊 作者

Java技术迷 | 出品

我们都知道,SpringCloud是微服务的一站式解决方案,是众多组件的集合,而因为SpringCloud中几乎所有的组件使用的都是Netflix公司的产品,其中大部分已经进入了停止更新或者维护阶段。我们需要一些别的组件来代替它们,基于此,SpringCloud Alibaba诞生了,本篇文章我们就来了解一下SpringCloud Alibaba中的服务组件——Nacos。

服务注册与配置中心-Nacos

nacos是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台,在SpringCloud Alibaba中,我们使用nacos进行服务的注册发现、服务的配置管理。

首先下载nacos,官网地址 https://nacos.io/zh-cn/ :

点击下方的版本说明:

拖动到网页底部,点击下载压缩包,解压完成后得到如下的目录结构:

其中启动程序放在bin目录下,直接执行bin目录中的 startup.cmd 即可启动nacos:

这样就表示启动成功了,此时访问 http://localhost:8848/nacos :

默认的用户名和密码均为 nacos ,登录后即可来到nacos的后台管理系统:

服务注册

接下来我们试着编写一个服务并将其注册到nacos中。

首先创建父项目 springcloud-alibaba,将pom文件修改如下:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wwj</groupId>
<artifactId>springcloud-alibaba</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-alibaba</name>
<description>Demo project for Spring Boot</description>
<packaging>pom</packaging>

<modules>
<module>cloud-provider-payment8001</module>
</modules>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
</project>

然后创建支付服务提供者 cloud-provider-payment8001,修改pom文件如下:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-provider-payment8001</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>cloud-provider-payment8001</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>com.wwj</groupId>
<artifactId>springcloud-alibaba</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
......
</project>

重点是引入nacos的依赖,引入依赖后编写配置文件:

spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # nacos的服务中心地址
service: cloud-provier-payment # 服务名

server:
port: 8001 # 端口号

需要注意的是服务名是必须进行配置的,配置完成后在启动类上添加@EnableDiscoveryClient注解:

@EnableDiscoveryClient
@SpringBootApplication
public class CloudProviderPayment8001Application {
public static void main(String[] args) {
SpringApplication.run(CloudProviderPayment8001Application.class, args);
}
}

此时启动该服务,然后查看nacos的后台系统:

点击左侧的服务列表,即可看到我们注册到nacos中的服务。然后编写一个控制器用于模拟业务:

@RestController
public class PaymentController {

@Value("${server.port}")
private String port;

@GetMapping("/payment/nacos/{id}")
public String getPayment(@PathVariable("id") Integer id) {
return "nacos服务注册,端口号:" + port + "\t" + "id:" + id;
}
}

测试一下,访问 http://localhost:8001/payment/nacos/1:

业务正常。接下来创建第二个支付服务 cloud-provider-payment8002 ,代码直接拷贝刚才的服务即可,只需修改端口号为8002,其它都一样。

启动payment8002,查看nacos后台:

这样服务就注册成功了。

服务消费

有了服务提供者之后,我们理应创建服务消费者来消费这些服务,当然,消费者也是要注册到nacos中的,创建服务 cloud-comsumer-order9000,pom文件依然是引入nacos依赖,然后编写配置文件:

spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # nacos的服务中心地址
service: cloud-consumer-order # 服务名

server:
port: 9001 # 端口号

既然是服务消费,那就少不了服务调用,但是nacos已经为我们集成了ribbon,当我们引入nacos依赖的时候,ribbon依赖也随之引入进来了,所以我们可以直接使用ribbon实现负载均衡,那么首先就需要将ribbon注册到容器中:

@Configuration
public class MyApplicationConfig {

@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}

最后编写控制器并在主启动类上标注@EnableDiscoveryClient注解:

@RestController
public class OrderController {

/**
* 需要调用的服务
*/
public static final String SERVER_URL = "http://cloud-provier-payment";

@Autowired
private RestTemplate restTemplate;

@GetMapping("/consumer/payment/nacos/{id}")
public String paymentInfo(@PathVariable("id") Integer id) {
// 拼接请求地址
String reqUrl = SERVER_URL + "/payment/nacos/" + id;
return restTemplate.getForObject(reqUrl, String.class);
}
}

启动服务消费者,首先查看nacos后台:

服务注册成功, 测试一下业务代码,访问 http://localhost:9001/consumer/payment/nacos/1 :

而且支持负载均衡,默认采用轮询策略。

OpenFeign

ribbon虽然能够实现客户端的负载均衡和服务调用,但是稍显麻烦,缺点也很明显,需要在Controller层调用方法请求另外一个服务的Controller方法。为此,我们可以使用OpenFeign来改进这一过程,OpenFeign集成了ribbon,它更侧重服务之间的调用,当然也默认支持负载均衡。以 cloud-comsumer-order9001 服务为例,要想使用OpenFeign,我们首先需要引入依赖:

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>

引入依赖后我们无需注册RestTemplate,而是来编写一个接口:

@FeignClient("cloud-provier-payment")
public interface PaymentService {

@GetMapping("/payment/nacos/{id}")
public String getPayment(@PathVariable("id") Integer id);
}

首先在该接口上标注 @FeignClient("cloud-provier-payment") 注解,其中值为需要远程调用的服务名,在接口中定义方法,一般来说,方法的声明与需要调用的方法声明一致。

然后在启动类上标注@EnableFeignClients注解:

@EnableDiscoveryClient
@EnableFeignClients("com.wwj.cloudcomsumer.order.service")
@SpringBootApplication
public class CloudComsumerOrder9001Application {
public static void main(String[] args) {
SpringApplication.run(CloudComsumerOrder9001Application.class, args);
}
}

若是接口在启动类当前包及其子包下,则无需配置注解的值;接下来就可以编写业务方法了:

@RestController
public class OrderController {

@Autowired
private PaymentService paymentService;

@GetMapping("/consumer/payment/nacos/{id}")
public String paymentInfo(@PathVariable("id") Integer id) {
return paymentService.getPayment(id);
}
}

将接口直接注入进来,然后调用接口中的方法即可。启动项目,测试业务:

服务配置

在前面我们就说过,nacos既是服务的注册中心,也是服务的配置中心,接下来看看nacos如何对服务进行配置。

首先创建一个新的服务 cloud-config2001,然后引入依赖:

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-nacos-config</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>

我们同样需要将服务注册到nacos中,并且还需要额外配置nacos的配置中心:

spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # nacos的服务中心地址
service: cloud-config2001 # 服务名
config:
server-addr: 127.0.0.1:8848 # nacos的配置中心地址
file-extension: yaml # 指定配置文件格式为yaml
prefix: cloud-config2001 # DataId前缀

server:
port: 2001 # 端口号

这个配置文件有讲究,我们需要创建一个名为 bootstrap.yml 的配置文件,这是因为我们需要优先去配置中心获取所需的配置,当配置中心没有配置时,才使用本地的配置,而bootstrap.yml配置文件的优先级高于其它命名的配置文件,故需将配置写在bootstrap.yml中。

不要忘了在启动类上标注@EnableDiscoveryClient 注解。最后编写一个方法进行测试:

@RestController
@RefreshScope // 支持nacos的动态刷新功能
public class ConfigController {

@Value("${config.msg}")
private String msg;

@GetMapping("/get/msg")
public String getMsg() {
return msg;
}
}

在本地我们并没有编写关于config.msg的配置信息,只需在nacos中编写配置即可,步骤如下。首先点击左侧导航栏的配置列表,然后点击右侧的+号:

特别需要注意接下来这一步:

最底下的是配置的内容,最上面的是Data ID,这个Data ID非常有讲究,它遵循这样的一个命名规范:

${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}

在项目中我们并没有配置 ${spring.application.name} ,但我们配置了Data ID的前缀: prefix: cloud-config2001 ,这两个必须选其中一个进行配置;我们也没有配置 ${spring.profiles.active} ,然后配置了文件格式为yaml,所以Data ID为 cloud-config2001.yaml 。若是我们配置了:

spring:
profiles:
active: dev # 开发环境

则Data ID为:cloud-config2001-dev.yaml ,最后千万记得点击发布配置才能生效。启动项目,测试一下:

加上我们在控制器上标注了@RefreshScope注解,所以在nacos配置中心里修改配置后,就能够立马在项目中生效,无需重新启动项目。

配置管理

nacos作为配置中心,除了能够提供配置外,它还具有非常强大的功能,比如命名空间、配置分组等等,首先说说命名空间。命名空间是用来区分部署环境的,一个项目往往需要经历开发、测试、维护三个阶段,每个阶段的配置内容可能不尽相同,为此,可以创建三个命名空间来分别接管这三个阶段的配置;默认情况下会有一个 public 命名空间。然后是Data ID,前面我们已经了解过Data ID的组成结构,所以我们可以直接通过Data ID的不同来区分不同环境的配置,比如:

cloud-config2001-dev.yamlcloud-config2001-test.yamlcloud-config2001-prod.yaml

此时我们就能通过修改:

spring:
profiles:
active: dev
# active: test
# active: prod

来分别获取三个配置文件的配置。

接下来我们再来看看分组,默认情况下我们会有一个 DEFAULT_GROUP 分组,新建的配置文件都会被存放在该分组下,通过分组我们也能够区分部署环境的配置信息:

这三个配置文件名相同,但是分组分别属于开发、测试和生产环境,然后通过 group 属性指定即可:

spring:
cloud:
nacos:
config:
group: DEV_GROUP # 指定分组
# group: TEST_GROUP
# group: PROD_GROUP

最后是命名空间,通过命名空间,我们仍然能够实现同样的效果:

点击导航栏的命名空间,然后点击右侧的新建命名空间:

创建好命名空间后,nacos会为每个命名空间分配id:

然后配置一下命名空间:

spring:
cloud:
nacos:
config:
group: DEV_GROUP # 指定分组
namespace: d7e672f8-441e-449b-a143-1eca69122daa # 命名空间ID

此时服务会去寻找该命名空间下的指定分组的配置文件,若有环境指定,也需要加上,然后在nacos中新建配置文件:

在指定命名空间下创建配置文件即可。

本文作者:汪伟俊 为Java技术迷专栏作者 投稿,未经允许请勿转载。


1、最牛逼的 Java 日志框架,性能无敌,横扫所有对手!
2、把Redis当作队列来用,真的合适吗?
3、惊呆了,Spring Boot居然这么耗内存!你知道吗?
4、牛逼哄哄的 BitMap,到底牛逼在哪?
5、全网最全 Java 日志框架适配方案!还有谁不会?
6、30个IDEA插件总有一款适合你
7、Spring中毒太深,离开Spring我居然连最基本的接口都不会写了

点分享

点收藏

点点赞

点在看

浏览 64
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报