赞
踩
https://docs.spring.io/spring-boot/docs/3.2.0/maven-plugin/reference/htmlsingle/#packaging
用Spring Boot maven插件可以打包成可执行的jar或者war,里边包含了应用的依赖,可以使用java -jar
来运行。
打包成可执行的归档文件是用插件的repackage
goal,如下:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
注意:如果你继承了spring-boot-starter-parent
,这个execution已经预先定义了,ID为repackage
,因此,你只需要在你的pom.xml文件中增加插件的定义即可。下面是spring-boot-starter-parent`的POM中对该execution的预定义:
上面的例子会在Maven生命周期的打包阶段重新打包成一个jar
或者war
,里边包含任何在项目中定义的依赖。如果一个或多个依赖不需要打包进去(即需要排除),你可以使用exclude
选项。
最初的(即不可执行的)包默认会被重命名为.original
,但是也可以用一个定制的标识(classifier)保存最初的包。
spring-boot-devtools
和spring-boot-docker-compose
默认自动被排除在外。
这个插件会改写你的manifest,特别地,它会管理Main-Class和Start-Class条目,例如MANIFEST.MF文件:
Manifest-Version: 1.0
Created-By: Maven JAR Plugin 3.3.0
Build-Jdk-Spec: 20
Implementation-Title: myproject
Implementation-Version: 0.0.1-SNAPSHOT
Main-Class: org.springframework.boot.loader.launch.JarLauncher
Start-Class: myproject.com.thb.MyApplication
Spring-Boot-Version: 3.2.1
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Spring-Boot-Layers-Index: BOOT-INF/layers.idx
如果使用默认值得到的包无法正常运行,你必须在Spring Boot中配置值,而不是在jar插件中配置。在manifest中的Main-Class
被Spring Boot插件的layout
属性控制,示例如下:
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <mainClass>${start.class}</mainClass> <layout>ZIP</layout> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
layout
的值默认根据归档包类型(jar
或 war
)确定。可用的值如下:
WEB-INF/lib-provided
目录下面,以避免部署到servlet容器的时候冲突。为了有个直观的理解,先看一个用Spring Boot maven插件重新打包后的jar包解压后的内容布局:
D:. ├─BOOT-INF │ │ classpath.idx │ │ layers.idx │ │ │ ├─classes │ │ └─myproject │ │ └─com │ │ └─thb │ │ MyApplication.class │ │ │ └─lib │ jackson-annotations-2.15.3.jar │ jackson-core-2.15.3.jar │ jackson-databind-2.15.3.jar │ jackson-datatype-jdk8-2.15.3.jar │ jackson-datatype-jsr310-2.15.3.jar │ jackson-module-parameter-names-2.15.3.jar │ jakarta.annotation-api-2.1.1.jar │ jul-to-slf4j-2.0.9.jar │ log4j-api-2.21.1.jar │ log4j-to-slf4j-2.21.1.jar │ logback-classic-1.4.14.jar │ logback-core-1.4.14.jar │ micrometer-commons-1.12.1.jar │ micrometer-observation-1.12.1.jar │ slf4j-api-2.0.9.jar │ snakeyaml-2.2.jar │ spring-aop-6.1.2.jar │ spring-beans-6.1.2.jar │ spring-boot-3.2.1.jar │ spring-boot-autoconfigure-3.2.1.jar │ spring-boot-jarmode-layertools-3.2.1.jar │ spring-context-6.1.2.jar │ spring-core-6.1.2.jar │ spring-expression-6.1.2.jar │ spring-jcl-6.1.2.jar │ spring-web-6.1.2.jar │ spring-webmvc-6.1.2.jar │ tomcat-embed-core-10.1.17.jar │ tomcat-embed-el-10.1.17.jar │ tomcat-embed-websocket-10.1.17.jar │ ├─META-INF │ │ MANIFEST.MF │ │ │ ├─maven │ │ └─com.thb │ │ └─myproject │ │ pom.properties │ │ pom.xml │ │ │ └─services │ java.nio.file.spi.FileSystemProvider │ └─org └─springframework └─boot └─loader ├─jar │ ManifestInfo.class │ MetaInfVersionsInfo.class │ NestedJarFile$JarEntriesEnumeration.class │ NestedJarFile$JarEntryInflaterInputStream.class │ NestedJarFile$JarEntryInputStream.class │ NestedJarFile$NestedJarEntry.class │ NestedJarFile$RawZipDataInputStream.class │ NestedJarFile$ZipContentEntriesSpliterator.class │ NestedJarFile.class │ NestedJarFileResources.class │ SecurityInfo.class │ ZipInflaterInputStream.class │ ├─jarmode │ JarMode.class │ ├─launch │ Archive$Entry.class │ Archive.class │ ClassPathIndexFile.class │ ExecutableArchiveLauncher.class │ ExplodedArchive$FileArchiveEntry.class │ ExplodedArchive.class │ JarFileArchive$JarArchiveEntry.class │ JarFileArchive.class │ JarLauncher.class │ JarModeRunner.class │ LaunchedClassLoader$DefinePackageCallType.class │ LaunchedClassLoader.class │ Launcher.class │ PropertiesLauncher$Instantiator$Using.class │ PropertiesLauncher$Instantiator.class │ PropertiesLauncher.class │ SystemPropertyUtils.class │ WarLauncher.class │ ├─log │ DebugLogger$DisabledDebugLogger.class │ DebugLogger$SystemErrDebugLogger.class │ DebugLogger.class │ ├─net │ ├─protocol │ │ │ Handlers.class │ │ │ │ │ ├─jar │ │ │ Canonicalizer.class │ │ │ Handler.class │ │ │ JarFileUrlKey.class │ │ │ JarUrl.class │ │ │ JarUrlClassLoader$OptimizedEnumeration.class │ │ │ JarUrlClassLoader.class │ │ │ JarUrlConnection$ConnectionInputStream.class │ │ │ JarUrlConnection$EmptyUrlStreamHandler.class │ │ │ JarUrlConnection.class │ │ │ LazyDelegatingInputStream.class │ │ │ Optimizations.class │ │ │ UrlJarEntry.class │ │ │ UrlJarFile.class │ │ │ UrlJarFileFactory.class │ │ │ UrlJarFiles$Cache.class │ │ │ UrlJarFiles.class │ │ │ UrlJarManifest$ManifestSupplier.class │ │ │ UrlJarManifest.class │ │ │ UrlNestedJarFile.class │ │ │ │ │ └─nested │ │ Handler.class │ │ NestedLocation.class │ │ NestedUrlConnection$ConnectionInputStream.class │ │ NestedUrlConnection.class │ │ NestedUrlConnectionResources.class │ │ │ └─util │ UrlDecoder.class │ ├─nio │ └─file │ NestedByteChannel$Resources.class │ NestedByteChannel.class │ NestedFileStore.class │ NestedFileSystem.class │ NestedFileSystemProvider.class │ NestedPath.class │ ├─ref │ Cleaner.class │ DefaultCleaner.class │ └─zip ByteArrayDataBlock.class CloseableDataBlock.class DataBlock.class DataBlockInputStream.class FileChannelDataBlock$ManagedFileChannel.class FileChannelDataBlock$Tracker.class FileChannelDataBlock.class NameOffsetLookups.class VirtualDataBlock.class VirtualZipDataBlock$DataPart.class VirtualZipDataBlock.class Zip64EndOfCentralDirectoryLocator.class Zip64EndOfCentralDirectoryRecord.class ZipCentralDirectoryFileHeaderRecord.class ZipContent$Entry.class ZipContent$Loader.class ZipContent$Source.class ZipContent.class ZipDataDescriptorRecord.class ZipEndOfCentralDirectoryRecord$Located.class ZipEndOfCentralDirectoryRecord.class ZipLocalFileHeaderRecord.class ZipString$CompareType.class ZipString.class
用插件重新打包后的jar在BOOT-INF/classes
目录下面包含应用的类、在BOOT-INF/lib
目录下包含应用的依赖。类似,一个可执行的war在WEB-INF/classes
目录下包含应用的类,在WEB-INF/lib
和WEB-INF/lib-provided
目录下包含应用的依赖。
分层的归档文件和一个常规的重新打包的jar或war有相同的布局,但是有一个额外的元数据文件用来描述每一层。之所以再进一步分层,是因为在有的情况下,docker image需要从jar或war的内容创建,需要对层次进一步细分,以便它们可以被写到不同的层级。
默认,在元数据文件中定义了如下的层:
SNAPSHOT
的依赖。SNAPSHOT
的依赖。层的顺序很重要,因为它决定了当应用改变的时候,前面的层在多大程度上可以被缓存。默认的顺序是dependencies, spring-boot-loader, snapshot-dependencies, application
。最小可能会改变的先增加,然后跟着是更大可能改变的层。
重新打包后的归档文件默认包含layers.idx
文件,例如:
layers.idx
文件的内容:
如果想禁用分层级的jar和war这个特性,可以如下:
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layers>
<enabled>false</enabled>
</layers>
</configuration>
</plugin>
</plugins>
</build>
</project>
依赖于你的应用,如果你希望调整如何分层、增加新的层级,可以使用一个单独的配置文件,象下面这样注册:
<project> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <layers> <enabled>true</enabled> <configuration>${project.basedir}/src/layers.xml</configuration> </layers> </configuration> </plugin> </plugins> </build> </project>
配置文件描述了一个归档文件如何被分为不同的层次、以及这次层次的顺序。下面的例子显式了默认的层次结构怎样被显式地定义:
<layers xmlns="http://www.springframework.org/schema/boot/layers" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/boot/layers https://www.springframework.org/schema/boot/layers/layers-3.2.xsd"> <application> <into layer="spring-boot-loader"> <include>org/springframework/boot/loader/**</include> </into> <into layer="application" /> </application> <dependencies> <into layer="application"> <includeModuleDependencies /> </into> <into layer="snapshot-dependencies"> <include>*:*:*SNAPSHOT</include> </into> <into layer="dependencies" /> </dependencies> <layerOrder> <layer>dependencies</layer> <layer>spring-boot-loader</layer> <layer>snapshot-dependencies</layer> <layer>application</layer> </layerOrder> </layers>
这个layers XML格式包含下面三小节:
<application>
块:定义了应用类和资源应该怎么分层。<dependencies>
块:定义了依赖应该怎么分层。<layerOrder>
块:定义了各层被写入的顺序。org.springframework.boot:spring-boot-maven-plugin:3.2.0
重新打包已经存在的JAR 和 WAR,以便它们可以在命令行下使用java -jar
执行。
当然,可以使用layout=NONE
选项,但这只是简单地将嵌套的依赖打包进去,没有main类,因此不能被执行。
默认,Spring Boot maven插件重新打包生成的归档包会替换原来的(原来的没有包含依赖,不能使用java -jar
被执行)。例如,maven项目:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.thb</groupId>
<artifactId>myproject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 其它 -->
重新打包的可执行的jar包是myproject-0.0.1-SNAPSHOT.jar
原来的不可执行的jar包是myproject-0.0.1-SNAPSHOT.jar.original
如果想改变分类器,原来的jar包的名称保留不变,重新打包的可执行的jar包用另外一个名字,可以如下配置插件:
<project> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <id>repackage</id> <goals> <goal>repackage</goal> </goals> <configuration> <classifier>exec</classifier> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
如果你使用了spring-boot-starter-parent
,那么repackage
这个goal是自动执行的(id为repackage
),那么就可以只声明configuration
如下:
<project> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <id>repackage</id> <configuration> <classifier>exec</classifier> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
这个配置会产生两个jar包:原来的jar、以及被repackage
goal重新打包的jar。两个都会被透明地安装、部署。例如,在cmd窗口执行mvn package
命令:
到工程的target目录下查看:
如果你希望重新打包的jar的本地名字和项目的artifactId
属性定义的不同,可以使用标准的finalName
,如下:
<project> <build> <finalName>my-app</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <id>repackage</id> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
这个配置将会产生重新打包的jartarget/my-app.jar
。
默认,repackage
goal用重新打包的可执行的替换以前的。如果你希望只部署以前的jar,但又想用使用常规文件名运行你的应用,配置插件如下:
<project> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <id>repackage</id> <goals> <goal>repackage</goal> </goals> <configuration> <attach>false</attach> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
这个配置产生两个jar:原来的jar、以及repackage
goal生成的可执行的jar。只有原来的会被安装/部署。
默认,repackage
和run
goal将包含项目中定义的依赖。如果你想从可执行的jar包中排除某些依赖。
有两种方法可以从打包/运行中排除一个依赖:
groupId
和 artifactId
排除一个特定的依赖,可选地,如果需要,可以加上classifier
。groupId
下的任何artifact。下面例子只排除com.example:module1:
<project> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>com.example</groupId> <artifactId>module1</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
下下面例子排除com.example
组下的所有artifact:
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludeGroupIds>com.example</excludeGroupIds>
</configuration>
</plugin>
</plugins>
</build>
</project>
当一个分层的jar
或者 war
生成的时候,spring-boot-jarmode-layertools
jar会作为一个依赖增加到你的归档包中。有这个jar包在类路径下面,你可以用一个特别的模式拉起你的应用,在这种特别的模式下面,允许引导程序代码运行一些跟你的应用完全不同的功能,例如抽取层。如果你希望排除这个依赖,可以如下:
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layers>
<includeLayerTools>false</includeLayerTools>
</layers>
</configuration>
</plugin>
</plugins>
</build>
</project>
默认的设置将依赖划分为snapshot 和non-snapshot。但是,你可能有更加复杂的规则,例如,你可能希望将你项目的公司特有的依赖划分到一个专有的层中。下面的layers.xml
演示了这样的设置:
<layers xmlns="http://www.springframework.org/schema/boot/layers" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/boot/layers https://www.springframework.org/schema/boot/layers/layers-3.2.xsd"> <application> <into layer="spring-boot-loader"> <include>org/springframework/boot/loader/**</include> </into> <into layer="application" /> </application> <dependencies> <into layer="snapshot-dependencies"> <include>*:*:*SNAPSHOT</include> </into> <into layer="company-dependencies"> <include>com.acme:*</include> </into> <into layer="dependencies"/> </dependencies> <layerOrder> <layer>dependencies</layer> <layer>spring-boot-loader</layer> <layer>snapshot-dependencies</layer> <layer>company-dependencies</layer> <layer>application</layer> </layerOrder> </layers>
上面的设置创建了一个专门的company-dependencies
层,里边包含groupId为com.acme
的所有库。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。