首页 文章详情

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

Java技术迷 | 503 2021-05-14 20:31 0 0 0
UniSMS (合一短信)


汪伟俊 作者

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我居然连最基本的接口都不会写了

点分享

点收藏

点点赞

点在看

good-icon 0
favorite-icon 0
收藏
回复数量: 0
    暂无评论~~
    Ctrl+Enter