maven springboot多环境profile加载不同配置文件自由切换

1.情景展示

  声明:本文和springboot没有关系,本质是:maven与spring相互作用产生的效果,之所以标题使用它,是为了让更多人看到。

  在实际开发过程中,我们经常会有这样需求:

  开发环境或测试环境,使用测试数据库;生产环境使用正式数据库。

  日志级别、引用的jar包、打包方式有时也会不一样,这样,同一项目就会存在多个运行环境。

  对于初学者而言,通常的做法就是:

  开发的时候在配置文件使用相关配置信息;需要部署项目的时候,再将原有代码注释掉,重新配置一套环境;打完包,在本地调试的时候,再将生产环境配置注销掉,还原开发环境。

  首先,这种方法肯定是可行的,但经常改来改去,不便维护及拓展。

  下面,介绍一种更好的方案。

2.环境分析

  我们先来了解一下,环境的种类有哪些?

  • 开发环境:development,通常用dev表示;
  • 测试环境:test,通常使用test表示;
  • 预演环境:preview,通常使用prev表示,相当于试运行阶段,处于测试和正式阶段之间;
  • 生产环境:production,通常使用prod表示。

  基本上上面的4种环境,就涵盖了我们研发一种产品的所有阶段。

  这里,需要说明的是:环境的名称是可以自定义的,你可以定义成任何名称,只不过是上面4种是大家约定俗称的名字而已,无论是谁看到,就能立马明白什么意思;而如果你将名字定义成aa,也许只有你自己知道它代表的是哪个环境了。

  下面,我先讲一种大众化的多环境开发模式。

  第一,application.properties/yml,作为spring的主配置文件。

  由该配置文件来决定,哪个配置文件生效。

  通过spring.profiles.active来设置生效的配置文件,如上图所示,我使用的是dev,在启动项目时,spring会加载application-dev.properties

  第二,设置环境配置文件

   这种方式,很简单,容易上手,没什么好说的。

3.解决方案

   这里,介绍一种更为高级的使用方式。

  通过pom.xml的profile标签来管理环境,换句话说就是:使用maven来完成环境的管理,在使用maven命令进行打包时实现。

  打包形式、打包时是否跳过测试阶段、是否启用接口说明文档、日志级别、以及引用的jar包,通通由profile来管理,实现在多环境中共存。

  先来看看pom.xml的构成吧,关键代码展示:

<groupId>com.公司简称</groupId>
<artifactId>项目名称</artifactId>
<!--打包形式:通过maven的profile来决定打成war包还是打jar包(如果不配置packaging标签的话,默认值是jar)-->
<packaging>${project.packaging}</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>项目名称</name>
<description>项目简述</description>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.1.RELEASE</version>
</parent>

<properties>
    <!--指定tomcat内置版本(只对springboot内置tomcat生效)-->
    <!--<tomcat.version>8.5.0</tomcat.version>-->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <!--java版本-->
    <java.version>1.8</java.version>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <!--proguard版本-->
    <proguard.version>6.2.2</proguard.version>
    <!--spring版本号-->
    <spring.version>2.3.1.RELEASE</spring.version>
    <!--打包时是否跳过测试阶段(使用profile来指定打包时是否进行测试)-->
    <skipTests>${skipTests}</skipTests>

    <!--加载application-*.yml配置文件(通过该标签来指定即将生效的配置文件)-->
    <!--加载application-test.yml配置文件(profile需要勾选成test)-->
    <spring.profiles.active>test</spring.profiles.active>
    <!--基层(测试环境)-->
    <!--<spring.profiles.active>jc</spring.profiles.active>-->

    <!--加载application-prod.yml配置文件-->
    <!--这样,这里就可以根据实际需要,进行多个生产环境间的切换(profile需要勾选成prod)-->
    <!--基层(正式环境)-->
    <!--<spring.profiles.active>jc</spring.profiles.active>-->
</properties>

<!--根据不同的环境引用不同的jar包,最终统一打包到项目当中-->
<!--生产环境:prod,开发环境:dev,测试环境:test,预演环境:prev
使用maven命令打包介绍:
开发环境打包:mvn clean package -Dmaven.test.skip=true -P dev
测试环境打包:mvn clean package -Dmaven.test.skip=true -P test
生产环境打包:mvn clean package -Dmaven.test.skip=true -P prod
!!!另外,在idea中切换生产环境和开发环境时,需要重新导包!!!-->
<profiles>
    <!--开发环境-->
    <profile>
        <id>dev</id>
        <activation>
            <!-- 默认激活本环境 -->
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <!--加载application-dev.yml配置文件(profile需要勾选成dev)-->
            <spring.profiles.active>dev</spring.profiles.active>
            <!--environment这个节点是我自己取的:yml文件根据该标签的值来确定接口地址是正式地址还是测试地址-->
            <environment>development</environment>
            <!--是否是生产环境:通过配置该值,来决定是否启用knife4j-->
            <isProduction>false</isProduction>
            <!--日志级别-->
            <logLevel>DEBUG</logLevel>
            <!--打包方式:
                设置成jar包时,在idea中,不能通过插件的package进行打包,
                只能通过命令来实现:mvn clean package -Dmaven.test.skip=true -P dev
            -->
            <project.packaging>jar</project.packaging>
            <!--打包时,需要进行测试-->
            <skipTests>true</skipTests>
        </properties>
        <dependencies>
            <!--jsp不能够在jar中使用,只能够在War中使用
            所以,如果确定部署项目的时候以jar的形式运行的话,则项目就不能使用jsp了,
            因为,maven在执行打包命令时,jsp是不会被打包到jar包当中的-->
            <!-- 使用jsp引擎,springboot内置tomcat没有此依赖 -->
            <dependency>
                <groupId>org.apache.tomcat.embed</groupId>
                <artifactId>tomcat-embed-jasper</artifactId>
                <version>9.0.36</version>
            </dependency>
            <!--增加对 JSP 文件的支持-->
            <dependency>
                <groupId>org.apache.tomcat</groupId>
                <artifactId>tomcat-jsp-api</artifactId>
                <version>9.0.36</version>
            </dependency>
            <!-- 添加jstl标签库依赖模块 -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jstl</artifactId>
                <version>1.2</version>
            </dependency>
        </dependencies>
    </profile>
    <!--测试环境-->
    <profile>
        <id>test</id>
        <activation>
            <activeByDefault>false</activeByDefault>
        </activation>
        <properties>
            <environment>test</environment>
            <isProduction>false</isProduction>
            <logLevel>INFO</logLevel>
            <project.packaging>war</project.packaging>
            <skipTests>true</skipTests>
        </properties>
        <dependencies>
           <!--引用的jar包与生产环境一样,这里不再展示-->
        </dependencies>
    </profile>
    <!--预演环境-->
    <profile>
        <id>prev</id>
        <activation>
            <activeByDefault>false</activeByDefault>
        </activation>
        <properties>
            <environment>preview</environment>
            <isProduction>true</isProduction>
            <logLevel>INFO</logLevel>
            <project.packaging>war</project.packaging>
            <skipTests>true</skipTests>
        </properties>
        <dependencies>
           <!--引用的jar包与生产环境一样,这里不再展示-->
        </dependencies>
    </profile>
    <!--生产环境-->
    <!--在本地通过Application启动项目时,其本质还是使用的springboot的内置tomcat,由于内置tomcat不支持使用jsp,
    所以,此时是无法访问项目对应的jsp页面的,
    只有将其部署在tomcat上并启动SpringBootStartApplication才能正常访问-->
    <profile>
        <id>prod</id>
        <!-- 是否激活本环境 -->
        <activation>
            <activeByDefault>false</activeByDefault>
        </activation>
        <properties>
            <environment>production</environment>
            <isProduction>true</isProduction>
            <logLevel>ERROR</logLevel>
            <project.packaging>war</project.packaging>
            <!--打包时,跳过测试阶段(因为测试阶段会去连接数据库,正式数据库本地无法访问,会导致打包失败)-->
            <skipTests>true</skipTests>
        </properties>
        <!--项目中,编译和测试阶段用到的jar包,但tomcat中存在这些jar包,此时,在部署到tomcat中时,我们就需要把它们踢掉-->
        <dependencies>
            <!--内置tomcat(剔除该jar包)-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
                <!--只有编译和测试阶段生效-->
                <scope>provided</scope>
            </dependency>
            <!-- servlet依赖(只在开发时使用,因为部署到tomcat上时,tomcat有对应的jar包) -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <scope>provided</scope>
            </dependency>
            <!-- jstl标签库依赖 -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jstl</artifactId>
                <version>1.2</version>
                <scope>provided</scope>
            </dependency>
        </dependencies>
    </profile>
</profiles>
<!--配置项目的jar包仓库-->
<repositories>
    <!--阿里云仓库-->
    <repository>
        <id>central</id>
        <name>central maven</name>
        <url>https://maven.aliyun.com/repository/central</url>
        <!--<url>http://maven.aliyun.com/nexus/content/groups/public/</url>-->
    </repository>
    <!--maven官网-->
    <repository>
        <id>public</id>
        <name>public maven</name>
        <url>https://mvnrepository.com</url>
    </repository>
</repositories>
<!--jar包依赖-->
<dependencies>
    <!--公共类封装引用-->
    <dependency>
        <groupId>code.marydon.encapsulation</groupId>
        <artifactId>javaUtils</artifactId>
        <version>1.0</version>
    </dependency>
</dependencies>

  再来看看application.yml主配置文件

  这里的关键点在于:

  yml文件想要引用pom.xml中的property标签的值时,在要引用的标签名称两边加上@,即:@propertyName@;如果是properties文件想要引用,使用的是EL表达式,${propertyName}。

  这样,就将启用的配置文件的决定权交给了pom.xml。

  提示:

  在idea中,按住Ctrl键不松手,会跳转到对应pom.xml该标签所处位置。

  knife4j配置(如果没有,就忽略)

  实现的效果就是:开发环境和测试环境可以访问接口文档,预演环境和生产环境禁止访问。 

  数据库配置、日志配置等自定义配置不在主配置文件里放,放到对应的环境配置文件当中。

  假设,我们需要调用第三方的接口,而第三方接口也分测试地址和正式地址。

  那我们就可以在这里使用自定义标签,把正式接口和测试接口添加到配置文件当中。

  如果没有这种需求,就可以跳过。

 

  这样,我们分别获取到当前生效的是哪种环境,测试接口地址,正式接口地址,根据环境来决定最终调用哪个地址。 

  这只是环境的一种使用方式,还有一种应用场景是:根据环境来控制控制层的是否可见(特定请求只在特定环境生效),下篇文章会讲。 

  最后,来看看日志。

 

  日志级别,也由pom.xml的profile标签来决定。

  通常情况下,开发环境使用debug、测试环境使用info,生产环境使用error。

  每种环境的个性化需求,都可以通过这种方式来实现。

  如何正确使用多环境的切换?

  在idea中,想要项目完成环境的切换,至少需要完成前三步,一般项目在清空target目录后,idea会完成自动编译,如果没有那就是你没有设置自动编译;

  在idea中,经常会出现因idea自带的maven插件因环境切换失败导致项目编译失败的问题,这也没有办法,是idea自身的问题,重复上述步骤即可。 

  原理就是:maven插件会将yml文件中引用的标签的值写入对应的配置文件中。

  补充一点:

 

  如上图所示,一个地方会产生一个配置文件,而每个地方又可分为生产环境和测试环境,这时候,第一种方式就会显得力不从心。

  现在,我们只需要三步即可:

  增加一个配置文件,比如叫做:application-aa.yml;

  在pom.xml中,将原有的<spring.profiles.active>注释掉,添加一个同样的标签<spring.profiles.active>aa</spring.profiles.active>;

  选择要生效的环境,重新编译项目即可。

  这样,就实现了多区域多环境可以随意切换的效果。

写在最后

  哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!

 相关推荐:

 

posted @ 2020-12-27 17:02  Marydon  阅读(2021)  评论(2编辑  收藏  举报