SpringCloudAlibaba之服务注册与发现Nacos

1. 前言


Nacos 是阿里巴巴新的开源项目,可以快速实现动态服务发现、服务配置、服务元数据及流量管理。

本篇博客以实现服务注册与发现为主。

SpringCloud中也有一个同样优秀的服务注册与发现组件:Eureka,不过已经闭源了,这也是我为什么要学习 Nacos 的原因之一。

如果你也想了解 Eureka,那么请前往:SpringCloud之服务注册与发现Eureka+客户端Feign。个人认为两者的搭建流程和使用思路很相似,

核心的相同之处:

  1. 引入依赖
  2. 配置注册中心地址
  3. 添加注解

最大的不同之处:

  1. 服务端的搭建方式
  • Eureka Server 是自己手动搭建的
  • Nacos Server 需要通过源码构建或者直接下载的方式搭建

再来说说 Nacos Server 一些其他的重要信息

部署方式: 三种部署模式,分别对应不同的使用场景

  1. 单机模式:方便本地测试用
  2. 集群模式:适用于生产环境
  3. 多集群模式:用于多数据中心

启动方式: 两种启动方式,分别对应上面部署方式中的单机模式集群模式

  1. Linux / Unix / Mac 系统中单机模式启动需要添加 -m standalone 参数;反之,如果不加 -m standalone 参数则表示是集群模式启动。完整命令:sh startup.sh -m standalone
  2. Windows 系统中目前只支持单机模式启动,直接双击启动脚本文件。或完整命令:cmd startup.cmd

数据源: 两种数据源,分别可以在配置文件中指定

  1. Derby:内嵌在应用中的数据库(目前默认的数据源)
  2. MySQL:免费开源的关系型数据库(版本需要 5.6.5+)

Nacos Server 的版本选择: 目前官网推荐的稳定版本为 1.2.1


2. 源码


GitHub地址:https://github.com/intomylife/SpringCloud


3. 环境


  • JDK 1.8 +
  • Maven 3.2.x +
  • SpringBoot 2.0.6.RELEASE
  • SpringCloud Finchley.SR2
  • SpringCloudAlibaba 2.0.2.RELEASE

4. 开发工具


  • IntelliJ IDEA

5. 正文


5.1 commons 工程

5.1.1 commons 工程 - 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.zwc</groupId>
	<artifactId>discovery-commons</artifactId>
	<version>1.0.0</version>

	<!-- 工程名称和描述 -->
	<name>discovery-commons</name>
	<description>公用工程</description>

	<!-- 打包方式 -->
	<packaging>jar</packaging>

	<!-- 在 properties 下声明相应的版本信息,然后在 dependency 下引用的时候用 ${} 就可以引入该版本 jar 包了 -->
	<properties>
		<!-- 编码 -->
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<!-- jdk -->
		<java.version>1.8</java.version>

		<!-- SpringBoot -->
		<platform-bom.version>Cairo-SR3</platform-bom.version>
		<!-- SpringCloud -->
		<spring-cloud-dependencies.version>Finchley.SR2</spring-cloud-dependencies.version>
		<!-- SpringCloudAlibaba -->
		<spring-cloud-alibaba-dependencies.version>2.0.2.RELEASE</spring-cloud-alibaba-dependencies.version>
	</properties>

	<!-- 加入依赖 -->
	<dependencies>
		<!-- springboot 起步依赖 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
			<!-- 排除依赖 -->
			<exclusions>
				<exclusion>
					<groupId>ch.qos.logback</groupId>
					<artifactId>*</artifactId>
				</exclusion>
				<exclusion>
					<groupId>org.apache.logging.log4j</groupId>
					<artifactId>*</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<!-- springboot web 依赖 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<!-- 排除依赖 -->
			<exclusions>
				<exclusion>
					<groupId>ch.qos.logback</groupId>
					<artifactId>*</artifactId>
				</exclusion>
				<exclusion>
					<groupId>org.apache.logging.log4j</groupId>
					<artifactId>*</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<!-- log4j2 依赖 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-log4j2</artifactId>
		</dependency>
	</dependencies>

	<!-- 依赖 jar 包版本管理的管理器 -->
	<!-- 如果 dependencies 里的 dependency 自己没有声明 version 元素,那么 maven 就此处来找版本声明。 -->
	<!-- 如果有,就会继承它;如果没有就会报错,告诉你没有版本信息 -->
	<!-- 优先级:如果 dependencies 里的 dependency 已经声明了版本信息,就不会生效此处的版本信息了 -->
	<dependencyManagement>
		<dependencies>
			<!-- SpringBoot -->
			<dependency>
				<groupId>io.spring.platform</groupId>
				<artifactId>platform-bom</artifactId>
				<version>${platform-bom.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
			<!-- SpringCloud -->
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud-dependencies.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
			<!-- SpringCloudAlibaba -->
			<dependency>
				<groupId>com.alibaba.cloud</groupId>
				<artifactId>spring-cloud-alibaba-dependencies</artifactId>
				<version>${spring-cloud-alibaba-dependencies.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>

</project>
  • 引入一些共用依赖

5.1.2 commons 工程 - 项目结构

springcloudalibaba-nacos-discovery/discovery-commons/
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
    └── main
        ├── java
        │   └── com
        │       └── zwc
        │           └── core
        └── resources
            └── application.properties

5.2 service 工程

此工程下有五个模块:

应用名称 端口 描述
discovery-flyway-service 8082 辅助工程(自动创建数据库和表)
discovery-master-service / 注册中心(这里的注册中心工程其实就是 Nacos 的源码,放入项目中只是为了好找到)
discovery-provider-first-service 8090 提供者一号服务工程(对外提供服务)
discovery-provider-second-service 8091 提供者二号服务工程(对外提供服务)
discovery-consumer-service 8080 消费者服务工程(远程调用服务)

详细说明:

discovery-flyway-service: 前言中介绍了 Nacos Server 的数据源有两种,这里使用的是MySQL;而使用MySQL作为数据源后需要建一些基础表和插入一些基础数据,这时就需要手动操作,然而为了方便,我把这些“枯燥”的操作“简化”了:启动一下项目即可。可能唯一需要注意的就是,我本地的MySQL账号密码是root, 123456,如果和你的不一致,那么就在 application.properties 配置文件中更改一下。

discovery-master-service: 此工程中仅仅就复制粘贴了 Nacos Server 的源码,这里放入到项目中为了方便获取是一方面原因;还有另一方面是因为,需要在 Nacos Server 的配置文件中指定MySQL为数据源,以及配置MySQL数据库的连接信息,然而为了方便,我已经在 Nacos Server 的源码中改好了这些配置信息。可能唯一需要注意的就是,我本地的MySQL账号密码是root, 123456,如果和你的不一致,那么就在 nacos-1.2.1/distribution/conf/application.properties 配置文件中的 25,26 行更改一下。nacos-1.2.1/distribution/conf/application.properties 作为源码构建后的默认配置文件,所以这里先在源码中修改对应的配置信息,从而方便配合在后面使用脚本来快速启动 Nacos Server 服务。

discovery-provider-first-service: 作为提供者,对外提供一个服务,服务的具体内容就是输出一句话和当前服务的端口号。注意两个提供者的应用名称(spring.application.name)完全一致。

discovery-provider-second-service: 作为提供者,对外提供一个服务,服务的具体内容就是输出一句话和当前服务的端口号。注意两个提供者的应用名称(spring.application.name)完全一致。

discovery-consumer-service: 作为消费者,来远程调用服务,也就是调用上面的两个提供者提供的服务。


其他补充说明:


5.2.1 discovery-flyway-service

5.2.1.1 discovery-flyway-service - 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>

    <!-- 继承父 -->
    <parent>
        <groupId>com.zwc</groupId>
        <artifactId>discovery-service</artifactId>
        <version>1.0.0</version>
    </parent>

    <!-- 三座标 -->
    <groupId>com.zwc</groupId>
    <artifactId>discovery-flyway-service</artifactId>
    <version>1.0.0</version>

    <!-- 工程名称描述 -->
    <name>discovery-flyway-service</name>
    <description>辅助工程(自动创建数据库和表)</description>

    <!-- 打包方式 -->
    <packaging>jar</packaging>

    <!-- 在 properties 下声明相应的版本信息,然后在 dependency 下引用的时候用 ${} 就可以引入该版本 jar 包了 -->
    <properties>
        <!-- ali 连接池 -->
        <druid.version>1.1.9</druid.version>
    </properties>

    <!-- 加入依赖 -->
    <dependencies>
        <!-- 数据库访问依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!-- mysql 依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- ali 连接池依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <!-- 数据库版本管理 依赖 -->
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
        </dependency>
    </dependencies>

    <!-- 插件依赖 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
  • 此工程的作用和目的就是为了自动创建数据库和表,所以引入数据库flyway相关依赖

5.2.1.2 discovery-flyway-service - application.properties 配置文件

# 端口
server.port=8082


# 数据源
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/nacos_config?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=PRC&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456


## flyway    注:可以完全不用配置
### sql 脚本的位置,默认为 classpath:db/migration。可手动指定
#spring.flyway.locations=classpath:db/migration
###  指定数据源,如果没有指定的话,将使用配置的主数据源
#spring.flyway.url=jdbc:mysql://127.0.0.1:3306/nacos_config?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=PRC&useSSL=false
### Flyway 管理的 Schema 列表,区分大小写。默认连接对应的默认 Schema
### 如果这里明确指定了库名,那么在 spring.flyway.url 连接中指定的库名将无效
#spring.flyway.schemas=nacos_config
### 用户名
#spring.flyway.user=root
### 密码
#spring.flyway.password=123456
### 开启,默认开启
#spring.flyway.enabled=true
  • 配置了连接数据库的基本信息,如果账号密码与你的不一致记得修改一下
  • 由于flyway默认会取数据源的配置信息,所以这里关于flyway的配置全部注释,主要为了如果是使用我的源代码测试,数据源的信息可以少改一个地方,我的本地MySQL密码是 123456,大家可能和我不一样

5.2.1.3 discovery-flyway-service - 自动创建数据库

package com.zwc.flyway.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * @ClassName InitDatabaseConfig
 * @Desc TODO   自动创建数据库
 * @Date 2020/6/21 8:38 PM
 * @Version 1.0
 */
@Configuration
public class InitDatabaseConfig {

    private static final Logger LOGGER = LoggerFactory.getLogger(InitDatabaseConfig.class);

    /**
     * 读取配置文件中数据库的连接信息
     */
    /**
     * 驱动名称
     */
    @Value("${spring.datasource.driver-class-name}")
    private String driverClassName;
    /**
     * 地址
     */
    @Value("${spring.datasource.url}")
    private String url;
    /**
     * 用户名
     */
    @Value("${spring.datasource.username}")
    private String username;
    /**
     * 密码
     */
    @Value("${spring.datasource.password}")
    private String password;


    /*
      * @ClassName InitDatabaseConfig
      * @Desc TODO  创建数据库
      * @Date 2020/6/22 8:58 AM
      * @Version 1.0
     */
    @Bean(name = "dataSource")
    public DataSource dataSource() {
        LOGGER.info("==================================== InitDatabaseConfig -> dataSource -> 开始创建数据库 ====================================");
        // 数据库连接对象
        Connection connection = null;
        Statement statement = null;
        try {

            // 如果尝试去连接不存在的数据库会报错,所以这里连接的时候不带数据库名称
            String connectionUrl = url.replace(("/" + (url.substring(0, url.indexOf("?"))).substring(((url.substring(0, url.indexOf("?"))).lastIndexOf("/")) + 1)), "");
            // 从连接地址中截取出数据库名称
            String databaseName = (url.substring(0, url.indexOf("?"))).substring(((url.substring(0, url.indexOf("?"))).lastIndexOf("/")) + 1);

            // 设置驱动
            Class.forName(driverClassName);
            // 连接数据库
            connection = DriverManager.getConnection(connectionUrl, username, password);
            statement = connection.createStatement();

            // 创建数据库
            statement.executeUpdate("create database if not exists `" + databaseName + "` default character set utf8mb4 COLLATE utf8mb4_general_ci");

        }catch (Exception e) {
            e.printStackTrace();
            LOGGER.info("==================================== InitDatabaseConfig -> dataSource -> 创建数据库出错:" + e.getMessage() + " ====================================");
        }finally {
            try {
                // 关闭连接
                statement.close();
                connection.close();
            }catch (SQLException e) {
                LOGGER.info("==================================== InitDatabaseConfig -> dataSource -> 关闭数据库出错:" + e.getMessage() + " ====================================");
            }
            LOGGER.info("==================================== InitDatabaseConfig -> dataSource -> 创建数据库结束 ====================================");
        }

        // 创建数据源
        DruidDataSource druidDataSource = new DruidDataSource();
        // 设置数据源
        druidDataSource.setDriverClassName(driverClassName);
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        // 返回数据源
        return druidDataSource;
    }

}
  • 使用@Configuration标注自定义配置类,在应用上下文加载时初始化

5.2.1.4 discovery-flyway-service - 自动新建数据表

由于引入了flyway-core依赖,所以只需要把初始化 sql 放在 flyway 默认会去读取的db/migration目录中,就可以了。具体内容可在源码中查看,就不粘贴出来占篇幅了。

5.2.1.5 discovery-flyway-service - 启动项目

  1. 确认并修改好数据库的连接信息后,启动项目;发现项目启动后就自动停止了,只要不报错,这里就是正常的,控制台会打印如下日志信息:
2020-07-04 18:35:34.120  INFO 2036 --- [           main] c.zwc.flyway.config.InitDatabaseConfig   : ==================================== InitDatabaseConfig -> dataSource -> 开始创建数据库 ====================================
2020-07-04 18:35:34.347  INFO 2036 --- [           main] c.zwc.flyway.config.InitDatabaseConfig   : ==================================== InitDatabaseConfig -> dataSource -> 创建数据库结束 ====================================
  1. 这时到MySQL图形化连接工具中刷新本地库,发现多了一个nacos_config数据库,打开数据库,可以看到一些基础表已经被自动创建出来了
  2. 那么,discovery-flyway-service 工程的作用就到此结束了

5.2.2 discovery-master-service

此工程中只有 Nacos Server 的源码,就没有太多搭建上的说明,唯一需要注意的就是上面提到过的数据库连接账号密码,如果你的不是root, 123456,那么就去修改一下。

但是此处需要着重说明的是如何快速构建这个源码,当然,Nacos 官方文档中已经写的很详细了,这里就锦上添花一波,把一些命令再“封装”一下,达到一行命令就能快速启动 Nacos Server 服务的效果。

这里分别为本地快速开发测试以及日常使用两种不同的场景编写了脚本,放在了项目的 script 目录中

springcloudalibaba-nacos-discovery/
├── discovery-commons
├── discovery-service
└── script
    ├── daily-use
    │   ├── nacos-start.sh
    │   └── nacos-stop.sh
    └── quick-start
        ├── nacos-install.bat
        ├── nacos-install.sh
        ├── nacos-start.bat
        ├── nacos-start.sh
        ├── nacos-stop.bat
        └── nacos-stop.sh

quick-start 目录 - 快速开始:

  1. 使用IDEA打开 springcloudalibaba-nacos-discovery 项目
  2. 点击IDEA底部的Terminal终端入口
  3. 进入到项目根目录
MacBook-Pro:springcloudalibaba-nacos-discovery zouwencong$ pwd
/Users/zouwencong/JavaWork/my_spring_cloud/SpringCloud/springcloudalibaba-nacos-discovery
MacBook-Pro:springcloudalibaba-nacos-discovery zouwencong$ ls -all
total 32
drwxr-xr-x   7 zouwencong  staff    224 Jun 25 21:57 .
drwxr-xr-x  18 zouwencong  staff    576 Jul  3 13:54 ..
-rw-r--r--@  1 zouwencong  staff  12292 Jul  2 09:47 .DS_Store
drwxr-xr-x  10 zouwencong  staff    320 Jul  4 18:58 .idea
drwxr-xr-x  11 zouwencong  staff    352 Jun 28 16:08 discovery-commons
drwxr-xr-x  14 zouwencong  staff    448 Jul  2 16:41 discovery-service
drwxr-xr-x   5 zouwencong  staff    160 Jun 22 17:51 script
MacBook-Pro:springcloudalibaba-nacos-discovery zouwencong$ 
  1. 如果是Mac用户,先输入命令chmod +x script/quick-start/nacos-install.sh,然后再输入命令./script/quick-start/nacos-install.sh
  2. 如果是Windows用户,输入命令script\quick-start\nacos-install.bat
  3. 第一次构建时间会相对久一点,我自己这里用了大概两三分钟的样子,因为要到Maven中去下载SpringCloudAlibaba的相关依赖
  4. 如果是Mac用户,执行完对应命令后会有如下日志(截取最后关键部分):
...省略部分...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 38.467 s
[INFO] Finished at: 2020-07-04T19:42:13+08:00
[INFO] Final Memory: 110M/1588M
[INFO] ------------------------------------------------------------------------
...省略部分...
nacos is starting with standalone
nacos is starting,you can check the /Users/zouwencong/Downloads/SpringCloud-master/springcloudalibaba-nacos-discovery/discovery-service/discovery-master-service/nacos-1.2.1/distribution/target/naco-server-1.2.1/nacos/logs/start.out
[INFO] ----------------------------- end --------------------------------------
  1. 如果是Windows用户,执行完对应的命令后会有如下日志(截取最后关键部分):
...省略部分...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  01:18 min
[INFO] Finished at: 2020-07-04T19:52:11+08:00
[INFO] ------------------------------------------------------------------------
...省略部分...
2020-07-04 19:52:22,620 INFO Nacos started successfully in stand alone mode.

2020-07-04 19:52:22,857 INFO Initializing Servlet 'dispatcherServlet'

2020-07-04 19:52:22,865 INFO Completed initialization in 7 ms
  1. 这样 Nacos Server 就启动成功了,访问 Nacos Server 主页面:http://localhost:8848/nacos
  2. 账号密码:nacos, nacos
  3. 这里对应还有停止的脚本
  4. 如果是Mac用户,先输入命令chmod +x script/quick-start/nacos-stop.sh,然后再输入命令./script/quick-start/nacos-stop.sh
  5. 如果是Windows用户,发现当前Terminal框并没有可输入的地方了,所以这里想停止的话就先点击+ (New Session)按钮,然后再输入命令script\quick-start\nacos-stop.bat
  6. 那么如果想再启动,因为这里都构建过了,所以分别使用启动的脚本
  7. 如果是Mac用户,先输入命令chmod +x script/quick-start/nacos-start.sh,然后再输入命令./script/quick-start/nacos-start.sh
  8. 如果是Windows用户,输入命令script\quick-start\nacos-start.bat

daily-use 目录 - 日常使用:

我们可能以后项目中经常会用到 Nacos Server 服务,就像RedisMySQL一样,当做一个服务来启动,那么就先把刚刚编译构建后的目录(discovery-master-service/nacos-1.2.1/distribution/target/nacos-server-1.2.1/nacos)复制到本地。由于是作为日常使用的服务,所以再来设置一下日志目录

  1. 打开刚刚复制目录(discovery-master-service/nacos-1.2.1/distribution/target/nacos-server-1.2.1/nacos)下的 conf/application.properties 配置文件
  2. Ctrl + F 搜索server.tomcat.basedir
  3. 后面就可以指定存放日志的目录路径

由于Windows中启动 Nacos Server 不需要指定参数,所以在刚刚复制目录(discovery-master-service/nacos-1.2.1/distribution/target/nacos-server-1.2.1/nacos)下的 bin 目录中的 .bat 脚本可以直接双击使用;而Mac中为了方便,这里也写了一个日常使用的脚本,如何使用

  1. 复制 springcloudalibaba-nacos-discovery 项目中的 script/daily-use/nacos-start.sh 脚本文件和 script/daily-use/nacos-stop.sh 脚本文件到桌面
  2. 赋值执行权限:chmod +x nacos-start.shchmod +x nacos-stop.sh
  3. 右键nacos-start.sh文件
  4. 打开方式->其他...
  5. 启用:选择所有应用程序
  6. 勾选始终以此方式打开
  7. 点击实用工具
  8. 双击终端
  9. nacos-stop.sh 也同样设置一遍
  10. 都设置好后,现在只需要双击即可启动停止 Nacos Server 服务
  11. 当然,你具体会把构建后的目录复制到哪我是不知道的,所以脚本中的具体目录需要对应的修改一下
  12. nacos-start.sh -> 第 20 行
  13. nacos-stop.sh -> 第 8 行

5.2.3 discovery-provider-first-service

5.2.3.1 discovery-provider-first-service - 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>

    <!-- 继承父 -->
    <parent>
        <groupId>com.zwc</groupId>
        <artifactId>discovery-provider-first-service</artifactId>
        <version>1.0.0</version>
    </parent>

    <!-- 三座标 -->
    <groupId>com.zwc</groupId>
    <artifactId>discovery-provider-first-service-core</artifactId>
    <version>1.0.0</version>

    <!-- 工程名称描述 -->
    <name>discovery-provider-first-service-core</name>
    <description>提供者一号服务工程 - 核心</description>

    <!-- 打包方式 -->
    <packaging>jar</packaging>

    <!-- 在 properties下声明相应的版本信息,然后在dependency下引用的时候用 ${} 就可以引入该版本jar包了 -->
    <properties>

    </properties>

    <!-- 加入依赖 -->
    <dependencies>
        <!-- commons 工程依赖 -->
        <dependency>
            <groupId>com.zwc</groupId>
            <artifactId>discovery-commons</artifactId>
            <version>1.0.0</version>
        </dependency>

        <!-- api 工程依赖 -->
        <dependency>
            <groupId>com.zwc</groupId>
            <artifactId>discovery-provider-first-service-api</artifactId>
            <version>1.0.0</version>
        </dependency>

        <!-- 提供者消费者 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>

    <!-- 插件依赖 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
  • 加入 spring-cloud-starter-alibaba-nacos-discovery 依赖,表示会向 Nacos Server 中注册自己

5.2.3.2 discovery-provider-first-service - application.yml 配置文件

# 端口
server:
  port: 8090

spring:
  application:
    # 应用名称
    name: say-hello
  cloud:
    nacos:
      discovery:
        # 注册中心地址
        server-addr: 127.0.0.1:8848
        # 用户名
        username: nacos
        # 密码
        password: nacos
  • 注意此处配置注册中心地址的端口为 8848 也就是 Nacos Server 的服务端口
  • 有两个提供者工程,只有此处的端口不一致,此处端口为 8090,另一个端口为 8091。就不再赘述
  • 两个提供者工程作用是为了达到负载均衡的效果
  • spring.application.name:应用名称,被消费者调用时需要用到
  • 注意这里还配置了 Nacos Server 的用户名和密码,那是因为我在 discovery-master-service/nacos-1.2.1/distribution/conf/application.properties 配置文件中把 nacos.core.auth.enabled 设置为了 true,其实默认是 false 关闭的;开启后这里必须指定有效的用户名和密码,否则会报错

5.2.3.3 discovery-provider-first-service - controller 前端控制器

package com.zwc.first.api;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @ClassName SayHelloController
 * @Desc TODO   Say Hello
 * @Date 2019/5/15 15:28
 * @Version 1.0
 */
@RestController
public class SayHelloController {

    /*
     * @ClassName SayHelloController
     * @Desc TODO   读取配置文件中的端口
     * @Date 2019/5/15 15:49
     * @Version 1.0
     */
    @Value("${server.port}")
    private String port;

    /*
     * @ClassName SayHelloController
     * @Desc TODO   Say Hello
     * @Date 2019/5/15 15:30
     * @Version 1.0
     */
    @RequestMapping("/hello")
    public String hello(){
        return "Hello Spring Cloud Alibaba!!! port:" + port;
    }

}
  • 提供一个服务:输出 Hello 和端口

5.2.3.4 discovery-provider-first-service - 启动类

package com.zwc;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class DiscoveryProviderFirstServiceCoreApplication {

    public static void main(String[] args) {
        SpringApplication.run(DiscoveryProviderFirstServiceCoreApplication.class, args);
    }

}
  • 添加 @EnableDiscoveryClient 注解表示此服务要向注册中心注册自己

5.2.3.5 discovery-provider-first-service - 启动项目

  1. 项目启动成功后访问 http://localhost:8090/hello 看到输出内容Hello Spring Cloud Alibaba!!! port:8090
  2. 刷新 http://localhost:8848/nacos/#/serviceManagement(注册中心)可以看到服务已经被注册进来了
服务名 分组名称 集群数目 实例数 健康实例数 触发保护阈值 操作
say-hello DEFAULT_GROUP 1 1 1 false 详情 | 示例代码 | 删除
  1. 同理,还有一个提供者工程只是端口不一致,也启动起来
  2. 项目启动成功后访问 http://localhost:8091/hello 看到输出内容Hello Spring Cloud Alibaba!!! port:8091
  3. 再次刷新 http://localhost:8848/nacos/#/serviceManagement(注册中心)可以看到相同的服务有两个提供者
服务名 分组名称 集群数目 实例数 健康实例数 触发保护阈值 操作
say-hello DEFAULT_GROUP 1 2 2 false 详情 | 示例代码 | 删除

5.2.4 discovery-consumer-service

5.2.4.1 discovery-consumer-service - 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>

    <!-- 继承父 -->
    <parent>
        <groupId>com.zwc</groupId>
        <artifactId>discovery-consumer-service</artifactId>
        <version>1.0.0</version>
    </parent>

    <!-- 三座标 -->
    <groupId>com.zwc</groupId>
    <artifactId>discovery-consumer-service-core</artifactId>
    <version>1.0.0</version>

    <!-- 工程名称描述 -->
    <name>discovery-consumer-service-core</name>
    <description>消费者服务工程 - 核心</description>

    <!-- 打包方式 -->
    <packaging>jar</packaging>

    <!-- 在 properties下声明相应的版本信息,然后在dependency下引用的时候用 ${} 就可以引入该版本jar包了 -->
    <properties>

    </properties>

    <!-- 加入依赖 -->
    <dependencies>
        <!-- commons 工程依赖 -->
        <dependency>
            <groupId>com.zwc</groupId>
            <artifactId>discovery-commons</artifactId>
            <version>1.0.0</version>
        </dependency>

        <!-- api 工程依赖 -->
        <dependency>
            <groupId>com.zwc</groupId>
            <artifactId>discovery-consumer-service-api</artifactId>
            <version>1.0.0</version>
        </dependency>

        <!-- 提供者消费者 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- feign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>

    <!-- 插件依赖 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
  • 与提供者一致,加入 spring-cloud-starter-alibaba-nacos-discovery 依赖,表示会向 Nacos Server 中注册自己
  • 并且还需要加入 Feign 的起步依赖 spring-cloud-starter-openfeign 表示自己会远程调用其他服务

5.2.4.2 discovery-consumer-service - application.yml 配置文件

# 端口
server:
  port: 8080

spring:
  application:
    # 应用名称
    name: service-feign
  cloud:
    nacos:
      discovery:
        # 注册中心地址
        server-addr: 127.0.0.1:8848
        # 用户名
        username: nacos
        # 密码
        password: nacos

# 开启断路器
feign:
  hystrix:
    enabled: true
  • 注意此处配置注册中心地址的端口为 8848 也就是 Nacos Server 的服务端口
  • spring.application.name:应用名称,被消费者调用时需要用到,它在消费的同时也可以被消费
  • 注意这里还配置了 Nacos Server 的用户名和密码,那是因为我在 discovery-master-service/nacos-1.2.1/distribution/conf/application.properties 配置文件中把 nacos.core.auth.enabled 设置为了 true,其实默认是 false 关闭的;开启后这里必须指定有效的用户名和密码,否则会报错
  • hystrix 熔断功能需要主动开启才能生效

5.2.4.3 discovery-consumer-service - 服务调用

package com.zwc.consumer.feign;

import com.zwc.consumer.feign.fallback.FeignApiFallBack;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @ClassName FeignApi
 * @Desc TODO   使用 Feign 调用 Api - 接口
 * @Date 2019/5/15 16:11
 * @Version 1.0
 */
@FeignClient(value = "say-hello", fallback = FeignApiFallBack.class)
public interface FeignApi {

    /*
     * @ClassName FeignApi
     * @Desc TODO   调用远程 hello() 方法
     * @Date 2019/5/15 16:17
     * @Version 1.0
     */
    @RequestMapping("/hello")
    String hello();

}
  • 通过 @FeignClient 注解中 value = “say-hello” 来指定调用哪个服务
  • say-hello 就是提供者的 spring.application.name:应用名称
  • 通过 @FeignClient 注解中 fallback = FeignApiFallBack.class 来指定熔断时调用的方法
  • FeignApiFallBack 就是此接口(FeignApi)的实现类,对应的实现方法就是熔断时调用的方法
  • String hello();:可以发现,此方法就是提供者 SayHelloController 中的方法,只不过这里要定义成接口
  • 注意要与提供者具有相同返回值,相同方法名以及相同参数

5.2.4.4 discovery-consumer-service - Fallback(FeignApiFallBack)

package com.zwc.consumer.feign.fallback;

import com.zwc.consumer.feign.FeignApi;
import org.springframework.stereotype.Component;

/*
 * @ClassName FeignApi
 * @Desc TODO   fallback
 * @Date 2019/5/20 23:21
 * @Version 1.0
 */
@Component
public class FeignApiFallBack implements FeignApi {

    /*
     * @ClassName FeignApiFallBack
     * @Desc TODO   调用远程 hello() 方法失败时执行
     * @Date 2019/5/20 23:31
     * @Version 1.0
     */
    @Override
    public String hello() {
        return "Oh! Call say-hello fail.";
    }

}
  • 使用 @Component 注解把此类交给 Spring 管理
  • 实现了 FeignApi 接口,提供熔断时对应的方法

5.2.4.5 discovery-consumer-service - controller 前端控制器(消费服务)

package com.zwc.consumer.controller;

import com.zwc.consumer.feign.FeignApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @ClassName FeignController
 * @Desc TODO   使用 Feign 调用 Api - 前端控制器
 * @Date 2019/5/15 16:18
 * @Version 1.0
 */
@RestController
public class FeignController {

    @Autowired(required = false)
    private FeignApi feignApi;

    /*
     * @ClassName FeignController
     * @Desc TODO   调用远程 hello() 方法
     * @Date 2019/5/15 16:20
     * @Version 1.0
     */
    @RequestMapping("/feign")
    public String feign(){
        return feignApi.hello();
    }

}
  • 使用 @Autowired 注解装配 Bean,通过此 Bean 中的方法调用服务
  • 此类对外暴露接口,调用的实则是提供者的服务

5.2.4.6 discovery-consumer-service - 启动类

package com.zwc;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class DiscoveryConsumerServiceCoreApplication {

    public static void main(String[] args) {
        SpringApplication.run(DiscoveryConsumerServiceCoreApplication.class, args);
    }

}
  • 添加 @EnableDiscoveryClient 注解表示此服务要向注册中心注册自己
  • 添加 @EnableFeignClients 注解表示开启 Feign 功能进行远程调用

5.2.4.7 discovery-consumer-service - 启动项目

  1. 项目启动成功后多次访问 http://localhost:8080/feign
  2. 可以发现轮流输出Hello Spring Cloud Alibaba!!! port:8090Hello Spring Cloud Alibaba!!! port:8091
  3. 此时已经达到了负载均衡的效果
  4. 再次刷新 http://localhost:8848/nacos/#/serviceManagement(注册中心)可以看到此时多了一个消费者
服务名 分组名称 集群数目 实例数 健康实例数 触发保护阈值 操作
service-feign DEFAULT_GROUP 1 1 1 false 详情 | 示例代码 | 删除
say-hello DEFAULT_GROUP 1 2 2 false 详情 | 示例代码 | 删除

5.3 service 工程 - 项目结构

springcloudalibaba-nacos-discovery/discovery-service/
├── discovery-consumer-service
│   ├── discovery-consumer-service-api
│   ├── discovery-consumer-service-core
│   ├── mvnw
│   ├── mvnw.cmd
│   └── pom.xml
├── discovery-flyway-service
│   ├── mvnw
│   ├── mvnw.cmd
│   ├── pom.xml
│   └── src
├── discovery-master-service
│   ├── mvnw
│   ├── mvnw.cmd
│   ├── nacos-1.2.1
│   └── pom.xml
├── discovery-provider-first-service
│   ├── discovery-provider-first-service-api
│   ├── discovery-provider-first-service-core
│   ├── mvnw
│   ├── mvnw.cmd
│   └── pom.xml
├── discovery-provider-second-service
│   ├── discovery-provider-second-service-api
│   ├── discovery-provider-second-service-core
│   ├── mvnw
│   ├── mvnw.cmd
│   └── pom.xml
├── mvnw
├── mvnw.cmd
└── pom.xml

6. 把项目使用 IntelliJ IDEA 打开

  1. 把项目从 GitHub 中下载到你的本地
  2. 打开 IntelliJ IDEA
  3. 点击 File -> Open
  4. 打开你下载到本地的项目目录
  5. springcloudalibaba-nacos-discovery(选择打开此工程)
  6. 如果是高版本的 IntelliJ IDEA,则在右下角会提示有一些工程可以导入,那么选择一键导入就可以了
  7. 如果是低版本的 IntelliJ IDEA,则手动来导入
  8. 点击右侧 Maven Projects 入口
  9. 点击 + (Add Maven Projects)
  10. 分别选择 discovery-commons 工程和 discovery-service 工程的 pom.xml 文件,点击 Open 按钮


希望能够帮助到你

over




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章