【问题标题】:Cannot get maven project.version property in a Spring application with @Value无法使用@Value 在 Spring 应用程序中获取 maven project.version 属性
【发布时间】:2016-12-23 08:41:11
【问题描述】:

如何在带有@Value 注解的 Spring Boot 应用程序中获取 maven project.version 属性?

【问题讨论】:

    标签: maven spring-boot


    【解决方案1】:

    在对如何在 SpringBoot 应用程序中获取 Maven 项目版本进行一些研究和试验后,我找不到任何适合我的东西。

    由于类加载器问题,使用清单绝对是一条糟糕的路径,即获得 Spring 找到的第一个清单,在我的情况下不是我的应用程序。

    我发现的一个解决方案是使用 maven 资源插件来“过滤”(替换)资源文件中的属性。在这种情况下,Spring application.properties

    以下是完成这项工作的步骤。

    在 pom 文件中,使用以下定义激活资源过滤:

    <resources>
        <resource>
            <filtering>true</filtering>
            <directory>src/main/resources</directory>
            <includes>
                <include>application.properties</include>
            </includes>
        </resource>
    </resources>
    

    application.properties 文件中:

    application.name=@project.artifactId@
    build.version=@project.version@
    build.timestamp=@timestamp@
    

    注意application.properties 文件中的@property@ 而不是${property}。

    spring-boot-starter-parent pom 将标准${} 分隔符重新定义为@

    <resource.delimiter>@</resource.delimiter>
    <!-- delimiter that doesn't clash with Spring ${} placeholders -->
    <delimiters>
        <delimiter>${resource.delimiter}</delimiter>
    </delimiters>
    

    然后可以像这样在 Spring 中使用 @Value 访问这些属性:

    @Value("${application.name}")
    private String applicationName;
    
    @Value("${build.version}")
    private String buildVersion;
    
    @Value("${build.timestamp}")
    private String buildTimestamp;
    

    A sample project is available here.

    【讨论】:

    • 您基本上解决了 Spring 文档所描述的内容:docs.spring.io/spring-boot/docs/current/reference/html/… 文档中的一点是,如果您使用 Spring Boot 父级,则无需显式定义资源过滤器。
    • 我们不使用 spring-boot-starter-parent,但我们不需要像您的回答和section 72.1.1 所说的那样添加分隔符配置。
    • 时间戳实际上应该类似于build.timestamp=@maven.build.timestamp@
    • 关于如何使用 yaml 执行此操作的任何建议?我正在尝试使用值周围的引号来转义“@”字符(即“@project.artifactId@”但在 Cent-OS 中,当我将应用程序作为 jar 运行时,属性没有得到解析
    • 虽然我的 pom.xml 中有这个部分,但我仍然在苦苦挣扎。问题是,我在测试/资源中有一个单独的application.yml。当您也想为那个启用过滤时,您需要一个类似于docs.spring.io/spring-boot/docs/current/reference/html/… 中提到的testResources 部分
    【解决方案2】:

    要在 Spring Boot 应用程序中访问 Maven 属性,我们只需要在 application.properties 中使用分隔符 @ 映射它们,如下所示:

    app.version=@project.version@
    app.name=@project.name@
    

    然后在应用中像普通属性一样使用它们,例如:

    @Service
    public class SomeService {
    
       @Value("${app.version}")
       private String appVersion;
    
       // other stuff
    }
    

    来源:Automatic Property Expansion Using Maven

    但是如果您使用 yaml 来存储应用程序属性,则可能需要将分隔符 @ 替换为其他分隔符,例如我们的 pom.xml 中的 ^

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.7</version>
        <configuration>
            <delimiters>
                <delimiter>^</delimiter>
            </delimiters>
            <useDefaultDelimiters>false</useDefaultDelimiters>
        </configuration>
    </plugin>
    

    或者更简单 - 只需替换 pom.xml 的 propeties 块中的变量 resource.delimiter

    <properties>
        <java.version>11</java.version>
        <resource.delimiter>^</resource.delimiter>
    </properties>
    

    然后在你的属性文件中使用它,例如:

    app:
      version: ^project.version^
      name: ^project.name^
    

    【讨论】:

    • 为什么我们需要更改 YML 的分隔符
    • @PrabhatYadav 通常默认的在 YAML 中不起作用
    • 仅供任何寻找此内容的人参考,除非我们将 @ 符号替换为 ^,否则 Spring Cloud Config Server 无法正确提供带有这些分隔符的 YAML 文件。
    【解决方案3】:

    有一种更简单的方法可以做到这一点,不需要添加 application.properties 或分隔符更改。 只需添加带有目标构建信息的插件和带有 bean BuildProperties 的 Autowire 启动类。

    <plugin>
    <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-maven-plugin</artifactId>
       <version>2.1.3.RELEASE</version>
       <executions>
         <execution>
           <goals>
             <goal>build-info</goal>
           </goals>
         </execution>
       </executions>
    </plugin>
    

    启动类会有

    @Autowired
      BuildProperties buildProperties;
    

    稍后在@PostConstruct的启动类中,您可以调用多个方法来检索构建时间戳版本工件名称、团体等

    
    private static final Logger LOGGER = LoggerFactory.getLogger(YourSpringApplication.class);
    
    @Autowired
    BuildProperties buildProperties;
    
    public static void main(String[] args) {
        SpringApplication.run(YourSpringApplication.class, args);
      }
    
    @PostConstruct
      private void logVersion() {
        LOGGER.info(buildProperties.getName());
        LOGGER.info(buildProperties.getVersion());
        LOGGER.info(buildProperties.get("time"));
        LOGGER.info(buildProperties.getGroup());
    }
    

    info 执行器将自动使用并在检测到此信息时显示此信息,并在发现时显示git information

    【讨论】:

    • 这是最干净的答案。 @MilanDesai 非常感谢!
    • 使用 SpringBoot 1.5.1 没有这样的 bean:Consider revisiting the conditions above or defining a bean of type 'org.springframework.boot.info.BuildProperties' in your configuration.
    • org.springframework.beans.factory.NoSuchBeanDefinitionException:没有可用的“org.springframework.boot.info.BuildProperties”类型的合格bean:
    【解决方案4】:

    这可能是因为您的主 pom 没有将 spring-boot-starter-parent 声明为其父 pom。 因为这样的话,过滤是默认完成的,不需要显式声明过滤

    对我来说,从:

    <parent>
        <groupId>com.mycompany</groupId>
        <artifactId>mycompany-parent</artifactId>
        <version>20</version>
    </parent>
    

    到:

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

    在我的应用程序主 pom.xml 中修复了该问题,而无需声明过滤。

    【讨论】:

      【解决方案5】:
      It works with @charactor.
       <resource>
                  <directory>src/main/resources</directory>
                  <filtering>true</filtering>
      </resource>
      

      并且...在您的 application.properties 或 appplication.yml 文件中...

      版本:@project.version@ 名称:@project.name@

      【讨论】:

        猜你喜欢
        • 2021-09-01
        • 2020-04-21
        • 2022-11-03
        • 1970-01-01
        • 2021-12-07
        • 2017-09-05
        • 1970-01-01
        • 1970-01-01
        • 2016-08-17
        相关资源
        最近更新 更多