本文将向大家介绍在SpringCloudAlibaba微服务架构中,如何实现多个微服务在不修改各自配置文件的情况下适配不同环境进行部署。

作者:后端小肥肠

1. 前言

在现代软件开发过程中,随着敏捷开发和持续集成的普及,开发团队越来越需要在多个环境中快速部署应用。这种需求促使开发者寻找更为灵活和高效的部署方案。尤其是在使用Spring Cloud Alibaba框架的项目中,如何在不修改配置文件的情况下实现环境的快速切换,成为了提高开发效率和降低环境导致的错误的关键。

2. 实现思路

2.1. SpringCloudAlibaba加载配置文件的顺序

Spring Cloud 通过 bootstrap.ymlapplication.yml 文件来加载应用程序的配置信息。这两个文件在 Spring Boot 应用程序中扮演着不同的角色,其加载顺序和原理如下:

2.1.1. 加载顺序:
  1. bootstrap.yml:首先加载 bootstrap.yml 文件。这里可以定义一些系统级别的配置信息,比如连接远程配置中心的地址、加密/解密相关的配置等。
  2. application.yml:然后加载 application.yml 文件。这里定义的是应用程序级别的配置信息,比如数据库连接信息、端口号等。
2.1.2. 加载的内容:
  1. bootstrap.yml 的加载
  • 当 Spring Boot 应用程序启动时,首先会加载 bootstrap.yml 文件。
  • 这个过程是在 Spring Boot 启动时的一个很早的阶段进行的。
  • bootstrap.yml 主要用于应用程序上下文创建之前需要的一些特殊配置,比如配置中心的地址、加密解密的相关配置等。
  1. application.yml 的加载
  • 一旦 bootstrap.yml 加载完成,接着加载 application.yml 文件。
  • application.yml 文件包含了应用程序的各种配置,比如数据库配置、日志配置等。
  • 这些配置会在应用程序上下文创建后被加载。

2.2. 实现思路讲解

要实现在不修改配置文件情况下适配不同环境部署微服务,那么我们需要有一个common模块,common模块中有一个公共的配置文件,里面存放所有环境的Nacos配置信息:

JAVA 在哪里修改默认的服务器端口_spring cloud

如上图所示,下游服务只需要读取common模块中当前环境的配置信息,即可实现不修改配置文件的情况下快速适配各种环境进行部署(dev、test、prod)。

3. 开发环境搭建

3.1. 所需版本工具

依赖

版本

Spring Boot

2.6.3

Spring Cloud

2021.0.1

Java

1.8以上

Spring Cloud Alibaba

2021.0.1.0

spring-cloud-starter-alibaba-nacos-discovery

2021.0.1.0

spring-cloud-starter-alibaba-nacos-config

2021.0.1.0

Nacos

2.0.4

3.2. pom依赖

common模块依赖:

<dependencies>
        <!--Nacos依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.netflix.ribbon</groupId>
                    <artifactId>ribbon</artifactId>
                </exclusion>
            </exclusions>
        </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.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
</dependencies>

下游微服务在pom中引入common模块即可:

<dependency>
            <groupId>com.geoscene</groupId>
            <artifactId>image-integration-common</artifactId>
            <version>1.0-SNAPSHOT</version>
  </dependency>

4. 技术实践

4.1. common模块配置

在common模块resource文件夹下新增config文件夹,放入公共bootstrap.yml和application.yml:

JAVA 在哪里修改默认的服务器端口_docker_02

编写公共bootstrap.yml:

# 本地开发环境
spring:
  config:
    activate:
      on-profile: dev
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        username: nacos
        password: nacos
        namespace:
      config:
        server-addr: 127.0.0.1:8848
        username: nacos
        password: nacos
        namespace:
        file-extension: yaml

---
# 测试环境
spring:
  config:
    activate:
      on-profile: test
  cloud:
    nacos:
      discovery:
        server-addr: 测试环境参数
        username:  测试环境参数
        password:  测试环境参数
        namespace:  测试环境参数
      config:
        server-addr:  测试环境参数
        username:  测试环境参数
        password:  测试环境参数
        namespace:  测试环境参数
        file-extension: yaml
---
# 正式环境
spring:
  config:
    activate:
      on-profile: prod
  cloud:
    nacos:
      discovery:
        server-addr: 正式环境参数
        username: 正式环境参数
        password: 正式环境参数
        namespace: 正式环境参数
      config:
        server-addr: 正式环境参数
        username: 正式环境参数
        password: 正式环境参数
        namespace: 正式环境参数
        file-extension: yaml

编写公共application.yml: 

spring:
  mvc:
    pathmatch:
      # 该配置解决 Spring Boot 2.6.* 版本以上使用 Swagger 遇到的如下问题
      # Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
      matching-strategy: ant_path_matcher

4.2. 下游微服务配置

下游微服务配置分为以下几个步骤:

1. pom中新增模块名称标签:

<name>image-integration-system</name>

2. pom中新增环境配置相关标签:

<profiles>
        <profile>
            <id>dev</id>
            <properties>
                <spring.profiles.active>dev</spring.profiles.active>
            </properties>
            <!--没有指定其他profile为激活状态时,该profile就默认会被激活-->
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
        </profile>
        <profile>
            <id>test</id>
            <properties>
                <spring.profiles.active>test</spring.profiles.active>
            </properties>
        </profile>
        <profile>
            <id>prod</id>
            <properties>
                <spring.profiles.active>prod</spring.profiles.active>
            </properties>
        </profile>
    </profiles>

3.  编写bootstrap.yml

spring:
  application:
    name: @project.name@
  profiles:
    active: ${spring.profiles.active}

4. 编写application.yml并抽离至Naocs

JAVA 在哪里修改默认的服务器端口_微服务_03

5. 启动类上新增@EnableDiscoveryClient注解

5. 系统运行

5.1. 本地运行

在本机环境中选择运行环境即可启动微服务

JAVA 在哪里修改默认的服务器端口_java_04

运行程序

JAVA 在哪里修改默认的服务器端口_spring cloud_05

5.2. 测试环境及生产环境运行(Docker)

编写Dockerfile

# 使用更现代的 Java 基础镜像
FROM openjdk:8

# 设置容器内的时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 设置工作目录
WORKDIR /home/code

# 添加构建参数和环境变量
ARG profile


# 添加 jar 文件到工作目录
COPY ./xx.jar ./xx.jar

# 设置 Java 运行参数,启动应用
ENTRYPOINT ["java", "-Dfile.encoding=UTF-8", "-jar", "-Xmx1536m", "xx.jar","--spring.profiles.active=${profile}", "-c"]

编写Docker容器启动命令

docker run -id --name 容器名称 -p 端口号:端口号 --env profile=test 镜像名称:镜像版本

6. 结语

本文讲解了如何在SpringCloudAlibaba中实现在不修改配置文件情况下适配不同环境部署的具体步骤,有这方面需求的同学可以根据文章进行具体实操,也欢迎在评论区留言进行技术探讨。