目前大多數(shù)Spring Boot項(xiàng)目都會(huì)打成Jar包,所以什么War包、Ear包的就先不摸索了。
Jar包的秘密
我們先解壓一個(gè)Spring Boot應(yīng)用Jar包看看里面能不能找到一些蛛絲馬跡。在META-INF文件夾中找到了兩個(gè)相關(guān)的東西,一個(gè)是MANIFEST.MF:
Manifest-Version: 1.0 Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx Implementation-Title: spring-boot-version Implementation-Version: 1.0.23 Spring-Boot-Layers-Index: BOOT-INF/layers.idx Start-Class: cn.felord.SpringBootVersionApplication Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ Build-Jdk-Spec: 1.8 Spring-Boot-Version: 2.4.5 Created-By: Maven Jar Plugin 3.2.0 Main-Class: org.springframework.boot.loader.JarLauncher
里面包含了我定義的版本號(hào)1.0.23,Implementation-Version這個(gè)值好像通過代碼能夠獲得:
String version = this.getClass().getPackage().getImplementationVersion()
但是用IDE啟動(dòng)發(fā)現(xiàn)version=null,不過用java -jar運(yùn)行時(shí)version = 1.0.23。可能與IDE運(yùn)行并不是通過jar的方式有關(guān)。
另一個(gè)是pom.properties,Maven項(xiàng)目編譯會(huì)生成一個(gè)Properties配置文件:
artifactId=spring-boot-version groupId=cn.felord version=1.0.23
這豈不是讀取Properties文件就可以了?
String path = "META-INF/maven/cn.felord/spring-boot-version/pom.properties";
ClassPathResource resource = new ClassPathResource(path);
InputStream inputStream = resource.getInputStream();
try (InputStreamReader reader = new InputStreamReader(inputStream)) {
try (BufferedReader bufferedReader = new BufferedReader(reader)) {
bufferedReader.lines()
.forEach(System.out::println);
}
} catch (Exception ignored) {
}
這豈不是讀取Properties文件就可以了?
String path = "META-INF/maven/cn.felord/spring-boot-version/pom.properties";
ClassPathResource resource = new ClassPathResource(path);
InputStream inputStream = resource.getInputStream();
try (InputStreamReader reader = new InputStreamReader(inputStream)) {
try (BufferedReader bufferedReader = new BufferedReader(reader)) {
bufferedReader.lines()
.forEach(System.out::println);
}
} catch (Exception ignored) {
}
依然只能從jar讀取,而且比較麻煩。這兩種方式都要依賴jar包,有木有不單純依賴jar包的呢?
Maven資源插件過濾
Maven在構(gòu)建項(xiàng)目時(shí)可以通過資源插件將構(gòu)建屬性即pom.xml中的屬性注入到指定的資源文件中,具體操作為:
<build>
...
<resources>
<!-- include main.properties -->
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>main.properties</include>
</includes>
</resource>
</resources>
...
</build>
恰好spring-boot-starter-parent中已經(jīng)設(shè)置了這種方式。
<resource>
<directory>${basedir}/src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/application*.yml</include>
<include>**/application*.yaml</include>
<include>**/application*.properties</include>
</includes>
</resource>
如果你是application.properties,你可以通過下面的方式來接收版本號(hào):
application.version = ${project.version}
如果是application.yaml,你可以通過下面的方式來接收版本號(hào):
application: version: '@project.version@'
然后如何取值就不用多說了吧。這種方式不依賴jar包,使用起來也很簡單。
Spring Boot提供
Spring Boot其實(shí)已經(jīng)內(nèi)置了獲取項(xiàng)目構(gòu)建信息的自動(dòng)配置ProjectInfoAutoConfiguration,它包含一個(gè)條件BeanBuildProperties:
@ConditionalOnResource(
resources = {"${spring.info.build.location:classpath:META-INF/build-info.properties}"}
)
@ConditionalOnMissingBean
@Bean
public BuildProperties buildProperties() throws Exception {
return new BuildProperties(this.loadFrom(this.properties
.getBuild()
.getLocation(), "build", this.properties
.getBuild().getEncoding()));
}
這個(gè)BuildProperties提供了不少構(gòu)建信息:
public class BuildProperties extends InfoProperties {
public BuildProperties(Properties entries) {
super(processEntries(entries));
}
public String getGroup() {
return this.get("group");
}
public String getArtifact() {
return this.get("artifact");
}
public String getName() {
return this.get("name");
}
public String getVersion() {
return this.get("version");
}
public Instant getTime() {
return this.getInstant("time");
}
}
其中的條件build-info.properties可以通過Spring Boot插件spring-boot-maven-plugin執(zhí)行下面的命令生成:
mvn spring-boot:build-info
我們只需要配置插件為:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>
build-info
</goal>
</goals>
</execution>
</executions>
</plugin>
就能使得BuildProperties生效,我們可以輕松取得相關(guān)的信息:
{
"version" : "1.0.23",
"group" : "cn.felord",
"artifact" : "spring-boot-version",
"name" : "spring-boot-version",
"time" : {
"epochSecond" : 1620664643,
"nano" : 591000000
}
}
總結(jié)
今天介紹了幾種從通過API獲取項(xiàng)目構(gòu)建版本信息的方法,有什么用呢?主要用于項(xiàng)目監(jiān)控,發(fā)版審計(jì),DevOps等領(lǐng)域,包括Spring Boot的自定義banner。如果你的項(xiàng)目涉及到CI/CD,很可能要涉及到這一方面。 如果你知道更好用的獲取方法歡迎留言討論,我來拋磚引玉。
以上就是關(guān)于三種獲取 Java Maven 的版本號(hào)方式的詳細(xì)內(nèi)容,想要了解更多關(guān)于 Java Maven 項(xiàng)目的其他資料請(qǐng)關(guān)注W3Cschool其它相關(guān)文章!也希望大家能夠多多支持我們!