使用 Maven 時 manifest 的生成規則
譯自 http://maven.apache.org/plugins/maven-jar-plugin/examples/manifest-customization.html
默認的 Manifest
由 Maven Archiver 創建的默認的 manifest 文件包含以下內容
Manifest-Version: 1.0
Created-By: Apache Maven ${maven.version}
Build-Jdk: ${java.version}
注意:Build-Jdk項 不會考慮工具鏈配置,這是和運行Maven實例時相同的JDK版本
增加實現和規范細節(Adding Implementation And Specification Details)
maven-jar-plugin 從 2.1 版本開始,開始使用 3.5.0 版本的 Maven Archiver, 該版本的 Maven Archiver 默認不會向 manifest 中添加 Implementation 和 Specification 細節。如果需要這些,你需要顯示進行配置。
注意:由於這是 Maven Archive 最近才有的變動,有些插件可能會還沒有開始采用它。你需要檢查相關插件的文檔。這個例子中,我們使用 maven-jar-plugin 2.1,這是插件可以使用該特性的第一個版本。
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.1</version>
...
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
</archive>
</configuration>
...
</plugin>
</plugins>
</build>
...
</project>
生成的 manifest 文件內容如下
Manifest-Version: 1.0
Created-By: Apache Maven ${maven.version}
Build-Jdk: ${java.version}
Specification-Title: ${project.name}
Specification-Version: ${project.artifact.selectedVersion.majorVersion}.${project.artifact.selectedVersion.minorVersion}
Specification-Vendor: ${project.organization.name}
Implementation-Title: ${project.name}
Implementation-Version: ${project.version}
Implementation-Vendor: ${project.organization.name}
注意:如果你的 pom.xml 文件中沒有 <organization>/<name> 元素,則 Specification-Vendor 和 Implementation-Vendor 條目不會出現在 manifest 文件中
自定義 Customization the Manifest
默認的 manifest 可以通過 archive 配置項來改變。下面例子中你可以找到一些可用的配置項。更多的信息參見 Maven Archiver reference
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<index>true</index>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestEntries>
<mode>development</mode>
<url>${project.url}</url>
<key>value</key>
</manifestEntries>
</archive>
</configuration>
...
</plugin>
</plugins>
</build>
...
</project>
Manifest 條目(Manifest Entries)
如果你發現 Maven Archiver 配置項不足以操作 manifest,則可以向 manifest 添加自己的條目。 這是通過<manifestEntries>
配置元素來完成的。
在下面的例子中,我們將通過在 maven-jar-plugin 的<configuration> / <archive>
元素中指定所需的內容,向清單中添加一些條目。
注意:與這里的所有示例一樣,此配置可以在所有使用Maven Archiver的插件中使用,而不僅僅是本示例中的maven-jar-plugin。
<project>
<url>http://some.url.org/</url>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
...
<configuration>
<archive>
<manifestEntries>
<mode>development</mode>
<url>${project.url}</url>
</manifestEntries>
</archive>
</configuration>
...
</plugin>
</plugins>
</build>
...
</project>
如上所示,您可以使用字面值(literal values),也可以將POM中的值插入到字面值中,或者僅使用直接的POM表達式。 最后生成的 manifest 文件如下
Manifest-Version: 1.0
Created-By: Apache Maven ${maven.version}
Build-Jdk: ${java.version}
mode: development
url: http://some.url.org/
Note: If your pom.xml does not have the <url> element, referenced through interpolation, then the entry url will not be in the manifest.
Manifest Sections
<manifestSections>
元素提供了一種方式用來自定義 manifest 段 (manifest sections)。它包含一個 list of <manifestSection>
elements
注意:與這里的所有示例一樣,此配置可以在所有使用Maven Archiver的插件中使用,而不僅僅是本示例中的maven-jar-plugin。
使用如下配置
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
...
<configuration>
<archive>
<manifestSections>
<manifestSection>
<name>foo</name>
<manifestEntries>
<id>nice foo</id>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>bar</name>
<manifestEntries>
<id>nice bar</id>
</manifestEntries>
</manifestSection>
</manifestSections>
</archive>
</configuration>
...
</plugin>
</plugins>
</build>
...
</project>
生成的 manifest 文件如下
Manifest-Version: 1.0
Created-By: Apache Maven ${maven.version}
Build-Jdk: ${java.version}
Name: foo
id: nice foo
Name: bar
id: nice bar
設置 Classpath
添加一個 Class-Path Entry 到 Manifest
通過<addClasspath>
配置項, Maven Archiver 可以把你項目的 classpath 添加到 manifest,
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
...
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
...
</plugin>
</plugins>
</build>
...
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
...
</project>
生成的 manifest 如下
Manifest-Version: 1.0
Created-By: Apache Maven ${maven.version}
Build-Jdk: ${java.version}
Class-Path: plexus-utils-1.1.jar commons-lang-2.1.jar
讓 JAR 可執行 (Make The Jar Executable)
如果要創建可執行的jar文件,則需要相應地配置Maven Archiver。 您需要告訴它要使用哪個主類。 這是通過<mainClass>
配置元素完成的。 下面是一個示例pom.xml,配置為添加 classpath 並將full.qualified.MainClass類用作主類:
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
...
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
</configuration>
...
</plugin>
</plugins>
</build>
...
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
...
</project>
生成結果
Manifest-Version: 1.0
Created-By: Apache Maven ${maven.version}
Build-Jdk: ${java.version}
Main-Class: fully.qualified.MainClass
Class-Path: plexus-utils-1.1.jar commons-lang-2.1.jar
修改classpath,添加文件夾前綴(Altering The Classpath: Defining a Classpath Directory Prefix)
有時,能夠更改classpath 很有用,例如,在創建瘦的war文件(creating skinny war-files)時。 這可以通過<classpathPrefix>
配置元素來實現。
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
...
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
...
</project>
生成的 manifest 文件中的 classpath 看起來像這樣:
Class-Path: lib/plexus-utils-1.1.jar lib/commons-lang-2.1.jar
修改classpath,使用 Maven Repository-Style Classpath
Occasionally, you may want to include a Maven repository-style directory structure in your archive. If you wish to reference the dependency archives within those directories in your manifest classpath, try using the <classpathLayoutType>
element with a value of 'repository'
, like this:
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<classpathLayoutType>repository</classpathLayoutType>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
...
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
...
</project>
The manifest classpath produced using the above configuration would look like this:
Class-Path: lib/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.jar lib/commons-lang/commons-lang/2.1/commons-lang-2.1.jar
修改classpath,使用自定義的 classpath 格式 (Altering The Classpath: Using a Custom Classpath Format)
At times, you may have dependency archives in a custom format within your own archive, one that doesn't conform to any of the above classpath layouts. If you wish to define a custom layout for dependency archives within your archive's manifest classpath, try using the <classpathLayoutType>
element with a value of 'custom'
, along with the <customClasspathLayout>
element, like this:
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathLayoutType>custom</classpathLayoutType>
<customClasspathLayout>WEB-INF/lib/$${artifact.groupIdPath}/$${artifact.artifactId}-$${artifact.version}$${dashClassifier?}.$${artifact.extension}</customClasspathLayout>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
...
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
...
</project>
This classpath layout is a little more involved than the previous examples. To understand how the value of the <customClasspathLayout>
configuration is interpreted, it's useful to understand the rules applied when resolving expressions within the value:
- If present, trim off the prefix 'artifact.' from the expression.
- Attempt to resolve the expression as a reference to the Artifact using reflection (eg.
'artifactId'
becomes a reference to the method'getArtifactId()'
). - Attempt to resolve the expression as a reference to the ArtifactHandler of the current Artifact, again using reflection (eg.
'extension'
becomes a reference to the method'getExtension()'
). - Attempt to resolve the expression as a key in the special-case Properties instance, which contains the following mappings:
'dashClassifier'
: If the Artifact has a classifier, this will be'-$artifact.classifier'
, otherwise this is an empty string.'dashClassifier?'
: This is a synonym of'dashClassifier'
.'groupIdPath'
: This is the equivalent of'$artifact.groupId'
, with all'.'
characters replaced by'/'
.
The manifest classpath produced using the above configuration would look like this:
Class-Path: WEB-INF/lib/org/codehaus/plexus/plexus-utils-1.1.jar WEB-INF/lib/commons-lang/commons-lang-2.1.jar
Handling Snapshot Versions
Depending on how you construct your archive, you may have the ability to specify whether snapshot dependency archives are included with the version suffix '-SNAPSHOT'
, or whether the unique timestamp and build-number for that archive is used. For instance, the Assembly Plugin allows you to make this decision in the <outputFileNameMapping>
element of its <dependencySet
> descriptor section.
Forcing the use of -SNAPSHOT versions when using the simple (default) or repository classpath layout
To force the use of '-SNAPSHOT'
version naming, simply disable the <useUniqueVersions>
configuration element, like this:
<useUniqueVersions>false</useUniqueVersions>
Forcing the use of -SNAPSHOT versions with custom layouts
To force the use of '-SNAPSHOT'
version naming, simply replace '$artifact.version'
with '$artifact.baseVersion'
in the custom layout example above, so it looks like this:
<customClasspathLayout>WEB-INF/lib/${artifact.groupIdPath}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</customClasspathLayout>
The full example configuration would look like this:
<project> ... <build> <plugins> <plugin> <artifactId>maven-war-plugin</artifactId> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathLayoutType>custom</classpathLayoutType> <customClasspathLayout>WEB-INF/lib/${artifact.groupIdPath}/${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension}</customClasspathLayout> </manifest> </archive> </configuration> </plugin> </plugins> </build> ...</project>
使用你自己的 Manifest File
默認情況下,Maven Archiver 會為你產生 manifest 文件。你也可以通過配置項 manifestFile 來指定並使用你自己的 manifest 文件。自己指定的文件的內容,會被 merge 到 Maven Archiver 生成 manifest 文件中。如果你自己的文件和默認生成的文件有相同的條目,則自定義的條目會覆蓋掉自動生成的條目。
注意:與這里的所有示例一樣,此配置可以在所有使用Maven Archiver的插件中使用,而不僅僅是本示例中的maven-jar-plugin。
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
...
<configuration>
<archive>
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
...
</plugin>
</plugins>
</build>
...
</project>