IDEA Spring Boot Maven 多环境

多环境的作用在于允许在不同的运行环境中使用不同的配置。通常,在开发、测试和生产环境中,应用程序的配置可能会有所不同。这些配置包括数据库连接信息、日志级别、缓存设置、第三方服务的API密钥等等。使用多环境配置,可以根据当前运行的环境加载适当的配置,从而使应用程序在不同环境中具备不同的行为。

Spring Boot通过使用Maven或Gradle的profiles功能来实现多环境配置。在Maven中,可以为每个环境创建一个profile,并在对应的profile中定义相关的配置。例如,可以创建一个名为"dev"的profile,其中包含用于开发环境的配置,以及一个名为"prod"的profile,其中包含用于生产环境的配置。通过激活不同的profile,可以告诉Spring Boot在特定环境下使用哪个配置。

  1. 打开项目中的 pom.xml 文件。

  2. <profiles> 标签内,定义多个不同环境的 profile。每个 profile 包含一个唯一的 <id> 和相关的配置信息。例如:

    <profiles>
        <profile>
            <id>dev</id>
            <properties>
                <profiles.active>dev</profiles.active>
                <logging.level>debug</logging.level>
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
        </profile>
        <profile>
            <id>test</id>
            <properties>
                <profiles.active>test</profiles.active>
                <logging.level>debug</logging.level>
            </properties>
        </profile>
        <profile>
            <id>prod</id>
            <properties>
                <profiles.active>prod</profiles.active>
                <logging.level>info</logging.level>
            </properties>
        </profile>
    </profiles>
    
  3. <build> 标签内,使用 <resources> 元素来指定资源文件的过滤器(filters)路径。例如:

    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>application*</include>
                <include>bootstrap*</include>
                <include>banner.txt</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
    
  4. src/main/resources 目录下,创建与每个 profile 对应的资源文件。这些资源文件可以包含特定于每个环境的配置。例如,创建 application.yamlapplication-dev.yamlapplication-test.yamlapplication-prop.yaml 四个文件。

  5. 在每个资源文件中,使用 Maven 的过滤器语法引用 profile 中定义的属性。例如,在 application.yaml 文件中,你可以使用 @profiles.active@ 引用 properties 中的 profiles.active 属性;使用 @logging.level@ 引用 properties 中的 logging.level 属性。

    spring:
      profiles:
        active: @profiles.active@
    
    logging:
      level:
        me.pi.admin: @logging.level@
    
  6. 在 IDEA 的 Maven 项目窗口中,切换到 "Maven Projects" 视图。

  7. 展开项目的根节点,在 "Profiles" 下拉菜单中选择所需的环境(例如 devprod)。

  8. 在 IDEA 的工具栏中,点击 "Maven Projects" 窗口上的 "Reload All Maven Projects" 按钮,以刷新 Maven 项目并加载选定的 profile。

  9. 现在,你可以构建和运行项目,它将使用所选的环境配置。或者,你可以通过以下命令指定环境:

    $ mvn clean package -D maven.test.skip=true -P prod
    

Do not use @ for indentation 报错

当启动项目时可能出现如下错误:

org.yaml.snakeyaml.scanner.ScannerException: while scanning for the next token
found character '@' that cannot start any token. (Do not use @ for indentation)
 in 'reader', line 6, column 13:
        active: @profiles.active@
                ^

	at org.yaml.snakeyaml.scanner.ScannerImpl.fetchMoreTokens(ScannerImpl.java:460)
	at org.yaml.snakeyaml.scanner.ScannerImpl.checkToken(ScannerImpl.java:251)
	at org.yaml.snakeyaml.parser.ParserImpl$ParseBlockMappingValue.produce(ParserImpl.java:660)
	at org.yaml.snakeyaml.parser.ParserImpl.peekEvent(ParserImpl.java:166)
	at org.yaml.snakeyaml.comments.CommentEventsCollector$1.peek(CommentEventsCollector.java:59)
	at org.yaml.snakeyaml.comments.CommentEventsCollector$1.peek(CommentEventsCollector.java:45)
	at org.yaml.snakeyaml.comments.CommentEventsCollector.collectEvents(CommentEventsCollector.java:140)
	at org.yaml.snakeyaml.comments.CommentEventsCollector.collectEvents(CommentEventsCollector.java:119)
	at org.yaml.snakeyaml.composer.Composer.composeScalarNode(Composer.java:214)
	at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:184)
	at org.yaml.snakeyaml.composer.Composer.composeKeyNode(Composer.java:310)
	at org.yaml.snakeyaml.composer.Composer.composeMappingChildren(Composer.java:301)
	at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:286)
	at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:188)
	at org.yaml.snakeyaml.composer.Composer.composeValueNode(Composer.java:314)
	at org.yaml.snakeyaml.composer.Composer.composeMappingChildren(Composer.java:305)
	at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:286)
	at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:188)
	at org.yaml.snakeyaml.composer.Composer.composeValueNode(Composer.java:314)
	at org.yaml.snakeyaml.composer.Composer.composeMappingChildren(Composer.java:305)
	at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:286)
	at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:188)
	at org.yaml.snakeyaml.composer.Composer.getNode(Composer.java:115)
	at org.yaml.snakeyaml.constructor.BaseConstructor.getData(BaseConstructor.java:135)
	at org.springframework.boot.env.OriginTrackedYamlLoader$OriginTrackingConstructor.getData(OriginTrackedYamlLoader.java:103)
	at org.yaml.snakeyaml.Yaml$1.next(Yaml.java:514)
	at org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:198)
	at org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:166)
	at org.springframework.boot.env.OriginTrackedYamlLoader.load(OriginTrackedYamlLoader.java:88)
	at org.springframework.boot.env.YamlPropertySourceLoader.load(YamlPropertySourceLoader.java:50)
	at org.springframework.boot.context.config.StandardConfigDataLoader.load(StandardConfigDataLoader.java:54)
	at org.springframework.boot.context.config.StandardConfigDataLoader.load(StandardConfigDataLoader.java:36)
	at org.springframework.boot.context.config.ConfigDataLoaders.load(ConfigDataLoaders.java:108)
	at org.springframework.boot.context.config.ConfigDataImporter.load(ConfigDataImporter.java:128)
	at org.springframework.boot.context.config.ConfigDataImporter.resolveAndLoad(ConfigDataImporter.java:86)
	at org.springframework.boot.context.config.ConfigDataEnvironmentContributors.withProcessedImports(ConfigDataEnvironmentContributors.java:116)
	at org.springframework.boot.context.config.ConfigDataEnvironment.processInitial(ConfigDataEnvironment.java:240)
	at org.springframework.boot.context.config.ConfigDataEnvironment.processAndApply(ConfigDataEnvironment.java:227)
	at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:102)
	at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:94)
	at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:102)
	at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:87)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:131)
	at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:85)
	at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:66)
	at java.util.ArrayList.forEach(ArrayList.java:1257)
	at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:120)
	at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:114)
	at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:65)
	at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:343)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:301)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292)
	at me.pi.admin.AdminApplication.main(AdminApplication.java:32)

Process finished with exit code 1

这是由于环境未生效所致。

解决方法1:在 IDEA 的工具栏中,点击 "Maven Projects" 窗口上的 "Reload All Maven Projects" 按钮,以刷新 Maven 项目并加载选定的 profile。

我遇到的问题是每次打开项目或者更改了 profile 后都要点一下 Reload All Maven Projects,经过多次尝试,发现下面的方法可以解决每次都需要点刷新按钮的问题:

解决方法2:采用添加 BOM 的方式将 Spring Boot 引入项目中而不是通过继承父 pom 的方式:

<properties>
	<spring-boot.version>2.7.12</spring-boot.version>
</properties>
 <dependencyManagement>
     <dependencies>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-dependencies</artifactId>
             <version>${spring-boot.version}</version>
             <type>pom</type>
             <scope>import</scope>
         </dependency>
     </dependencies>
</dependencyManagement>

至于为何添加 BOM 的方式可行而继承父 pom 的方式不可行的原因欢迎讨论。

总结

使用多环境配置可以极大地简化在不同环境中部署和管理应用程序的过程。它使开发人员能够专注于特定环境的配置,从而提高开发效率并减少配置错误的可能性。此外,它还允许在不同环境中进行灵活的测试和部署,使得应用程序能够适应各种场景和需求。

项目实战

基于 Spring Boot 2.7.12、MyBatis-Plus、Spring Security 等主流技术栈构建的后台管理系统:

Gitee GitHub
后端 https://gitee.com/linjiabin100/pi-admin.git https://github.com/zengpi/pi-admin.git
前端 https://gitee.com/linjiabin100/pi-admin-web.git https://github.com/zengpi/pi-admin-web.git
posted @ 2023-06-15 15:14  ZnPi  阅读(142)  评论(0编辑  收藏  举报