如何在代码中获取Java应用当前的版本号?

举报
码农小胖哥 发表于 2022/03/31 23:18:08 2022/03/31
【摘要】 最近需要在项目中获取项目的版本号,最笨的方法莫过于硬编码一个版本号,当然我也是这么干的。不过闲下来的时候突发奇想Spring Boot项目中pom.xml定义的版本号能不能通过API获得呢?于是利用摸鱼的时间研究了这种无聊透顶的东西。 ❝ 目前大多数Spring Boot项目都会打成Jar包,所以什么War包、Ea...

最近需要在项目中获取项目的版本号,最笨的方法莫过于硬编码一个版本号,当然我也是这么干的。不过闲下来的时候突发奇想Spring Boot项目中pom.xml定义的版本号能不能通过API获得呢?于是利用摸鱼的时间研究了这种无聊透顶的东西。

目前大多数Spring Boot项目都会打成Jar包,所以什么War包、Ear包的就先不摸索了。

Jar包的秘密

我们先解压一个Spring Boot应用Jar包看看里面能不能找到一些蛛丝马迹。在META-INF文件夹中找到了两个相关的东西,一个是MANIFEST.MF


   
  1. Manifest-Version: 1.0
  2. Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
  3. Implementation-Title: spring-boot-version
  4. Implementation-Version: 1.0.23
  5. Spring-Boot-Layers-Index: BOOT-INF/layers.idx
  6. Start-Class: cn.felord.SpringBootVersionApplication
  7. Spring-Boot-Classes: BOOT-INF/classes/
  8. Spring-Boot-Lib: BOOT-INF/lib/
  9. Build-Jdk-Spec: 1.8
  10. Spring-Boot-Version: 2.4.5
  11. Created-By: Maven Jar Plugin 3.2.0
  12. Main-Class: org.springframework.boot.loader.JarLauncher

里面包含了我定义的版本号1.0.23Implementation-Version这个值好像通过代码能够获得:

String version = this.getClass().getPackage().getImplementationVersion()

  

但是用IDE启动发现version=null,不过用java -jar运行时version = 1.0.23。可能与IDE运行并不是通过jar的方式有关。

另一个是pom.properties:


   
  1. artifactId=spring-boot-version
  2. groupId=cn.felord
  3. version=1.0.23

这岂不是读取Properties文件就可以了?


   
  1.   String path = "META-INF/maven/cn.felord/spring-boot-version/pom.properties";
  2.   ClassPathResource resource = new ClassPathResource(path);
  3.   InputStream inputStream = resource.getInputStream();
  4.   try (InputStreamReader reader = new InputStreamReader(inputStream)) {
  5.       try (BufferedReader bufferedReader = new BufferedReader(reader)) {
  6.           bufferedReader.lines()
  7.                                 .forEach(System.out::println);
  8.          }
  9.      } catch (Exception ignored) {
  10.   }

依然只能从jar读取,而且比较麻烦。这两种方式都要依赖jar包,有木有不单纯依赖jar包的呢?

从配置文件读取

Maven在构建项目时可以通过资源插件将构建属性即pom.xml中的属性注入到指定的资源文件中,具体操作为:


   
  1. <build>
  2.   ...
  3.   <resources>
  4.     <!-- include main.properties -->
  5.     <resource>
  6.       <directory>src/main/resources</directory>
  7.       <filtering>true</filtering>
  8.       <includes>
  9.         <include>main.properties</include>
  10.       </includes>
  11.     </resource>
  12.   </resources>
  13.   ...
  14. </build>

恰好spring-boot-starter-parent中已经设置了这种方式。


   
  1.       <resource>
  2.         <directory>${basedir}/src/main/resources</directory>
  3.         <filtering>true</filtering>
  4.         <includes>
  5.           <include>**/application*.yml</include>
  6.           <include>**/application*.yaml</include>
  7.           <include>**/application*.properties</include>
  8.         </includes>
  9.       </resource>

如果你是application.properties,你可以通过下面的方式来接收版本号:

application.version = ${project.version}

  

如果是application.yaml,你可以通过下面的方式来接收版本号:


   
  1. application:
  2.   version: '@project.version@'

然后如何取值就不用多说了吧。这种方式不依赖jar包,使用起来也很简单。

Spring Boot提供

Spring Boot其实已经内置了获取项目构建信息的自动配置ProjectInfoAutoConfiguration,它包含一个条件BeanBuildProperties


   
  1.     @ConditionalOnResource(
  2.         resources = {"${spring.info.build.location:classpath:META-INF/build-info.properties}"}
  3.     )
  4.     @ConditionalOnMissingBean
  5.     @Bean
  6.     public BuildProperties buildProperties() throws Exception {
  7.         return new BuildProperties(this.loadFrom(this.properties
  8.                                                  .getBuild()
  9.                                                  .getLocation(), "build",                                                     this.properties
  10.                                                  .getBuild().getEncoding()));
  11.     }

这个BuildProperties提供了不少构建信息:


   
  1. public class BuildProperties extends InfoProperties {
  2.     public BuildProperties(Properties entries) {
  3.         super(processEntries(entries));
  4.     }
  5.     public String getGroup() {
  6.         return this.get("group");
  7.     }
  8.     public String getArtifact() {
  9.         return this.get("artifact");
  10.     }
  11.     public String getName() {
  12.         return this.get("name");
  13.     }
  14.     public String getVersion() {
  15.         return this.get("version");
  16.     }
  17.     public Instant getTime() {
  18.         return this.getInstant("time");
  19.     }
  20.    } 

其中的条件build-info.properties可以通过Spring Boot插件spring-boot-maven-plugin执行下面的命令生成:

mvn spring-boot:build-info

  

我们只需要配置插件为:


   
  1. <plugin>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-maven-plugin</artifactId>
  4.     <executions>
  5.         <execution>
  6.             <goals>
  7.                 <goal>
  8.                     build-info
  9.                 </goal>
  10.             </goals>
  11.         </execution>
  12.     </executions>
  13. </plugin>

就能使得BuildProperties生效,我们可以轻松取得相关的信息:


   
  1. {
  2.   "version" : "1.0.23",
  3.   "group" : "cn.felord",
  4.   "artifact" : "spring-boot-version",
  5.   "name" : "spring-boot-version",
  6.   "time" : {
  7.     "epochSecond" : 1620664643,
  8.     "nano" : 591000000
  9.   }
  10. }

总结

今天介绍了几种从通过API获取项目构建版本信息的方法,有什么用呢?主要用于项目监控,发版审计,DevOps等领域,包括Spring Boot的自定义banner也可以使用。算是一个锦上添花的小Tips,简单了解一下就好。

抱怨Swagger不好用?好吧我换一个好用的

2021-05-10

Spring Boot的 Docker打包插件哪个好用

2021-05-07

文章来源: felord.blog.csdn.net,作者:码农小胖哥,版权归原作者所有,如需转载,请联系作者。

原文链接:felord.blog.csdn.net/article/details/116677801

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。