标签:入门 addition standard out ret rip 生命周期 war dir
Spring Boot的Maven插件(Spring Boot Maven plugin)能够以Maven的方式为应用提供Spring Boot的支持,即为Spring Boot应用提供了执行Maven操作的可能。
Spring Boot Maven plugin能够将Spring Boot应用打包为可执行的jar或war文件,然后以通常的方式运行Spring Boot应用。
Spring Boot Maven plugin的最新版本为2017.6.8发布的1.5.4.RELEASE,要求Java 8, Maven 3.2及以后。
Spring Boot Maven plugin的5个Goals
配置pom.xml文件
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.0.1.RELEASE</version> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
mvn package spring-boot:repackage说明
Spring Boot Maven plugin的最主要goal就是repackage,其在Maven的package生命周期阶段,能够将mvn package生成的软件包,再次打包为可执行的软件包,并将mvn package生成的软件包重命名为*.original。
基于上述配置,对一个生成Jar软件包的项目执行如下命令
可以看到生成的两个jar文件,一个是*.jar,另一个是*.jar.original。在执行上述命令的过程中,Maven首先在package阶段打包生成*.jar文件;然后执行spring-boot:repackage重新打包,查找Manifest文件中配置的Main-Class属性,如下所示:
Manifest-Version: 1.0
Implementation-Title: gs-consuming-rest
Implementation-Version: 0.1.0
Archiver-Version: Plexus Archiver
Built-By: exihaxi
Implementation-Vendor-Id: org.springframework
Spring-Boot-Version: 1.5.3.RELEASE
Implementation-Vendor: Pivotal Software, Inc.
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.ericsson.ramltest.MyApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Created-By: Apache Maven 3.5.0
Build-Jdk: 1.8.0_131
注意,其中的Main-Class属性值为org.springframework.boot.loader.JarLauncher;
Start-Class属性值为com.ericsson.ramltest.MyApplication。
其中com.ericsson.ramltest.MyApplication类中定义了main()方法,是程序的入口。
通常,Spring Boot Maven plugin会在打包过程中自动为Manifest文件设置Main-Class属性,事实上该属性究竟作用几何,还可以受Spring Boot Maven plugin的配置属性layout控制的,示例如下
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>1.5.4.RELEASE</version> <configuration> <mainClass>${start-class}</mainClass> <layout>ZIP</layout> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin>
layout属性的值可以如下:
Main-Class: org.springframework.boot.loader.JarLauncher
Main-Class: org.springframework.boot.loader.warLauncher
Main-Class: org.springframework.boot.loader.PropertiesLauncher
RepackageMojo的关键方法execute:
@Override public void execute() throws MojoExecutionException, MojoFailureException { if (this.project.getPackaging().equals("pom")) { getLog().debug("repackage goal could not be applied to pom project."); return; } if (this.skip) { getLog().debug("skipping repackaging as per configuration."); return; } //得到项目中的原始的jar,就是使用maven-jar-plugin生成的jar File source = this.project.getArtifact().getFile(); //要写入的目标文件,就是fat jar File target = getTargetFile(); Repackager repackager = new Repackager(source) { //从source中寻找spring boot 应用程序入口的main方法。 @Override protected String findMainMethod(JarFile source) throws IOException { long startTime = System.currentTimeMillis(); try { return super.findMainMethod(source); } finally { long duration = System.currentTimeMillis() - startTime; if (duration > FIND_WARNING_TIMEOUT) { getLog().warn("Searching for the main-class is taking some time, " + "consider using the mainClass configuration " + "parameter"); } } } }; //如果插件中指定了mainClass就直接使用 repackager.setMainClass(this.mainClass); if (this.layout != null) { getLog().info("Layout: " + this.layout); repackager.setLayout(this.layout.layout()); } //寻找项目运行时依赖的jar,过滤后 Set<Artifact> artifacts = filterDependencies(this.project.getArtifacts(), getFilters(getAdditionalFilters())); //将Artifact转化成Libraries Libraries libraries = new ArtifactsLibraries(artifacts, this.requiresUnpack, getLog()); try { LaunchScript launchScript = getLaunchScript(); //进行repackage repackager.repackage(target, libraries, launchScript); } catch (IOException ex) { throw new MojoExecutionException(ex.getMessage(), ex); } if (this.classifier != null) { getLog().info("Attaching archive: " + target + ", with classifier: " + this.classifier); this.projectHelper.attachArtifact(this.project, this.project.getPackaging(), this.classifier, target); } else if (!source.equals(target)) { this.project.getArtifact().setFile(target); getLog().info("Replacing main artifact " + source + " to " + target); }
基本上重要的步骤都有注释,应该不难理解的。再来看下面,当然也不是重点,看看就行
public void repackage(File destination, Libraries libraries, LaunchScript launchScript) throws IOException { if (destination == null || destination.isDirectory()) { throw new IllegalArgumentException("Invalid destination"); } if (libraries == null) { throw new IllegalArgumentException("Libraries must not be null"); } if (alreadyRepackaged()) { return; } destination = destination.getAbsoluteFile(); File workingSource = this.source; //如果源jar与目标jar的文件路径及名称是一致的 if (this.source.equals(destination)) { //将源jar重新命名为原名称+.original,同时删除原来的源jar workingSource = new File(this.source.getParentFile(), this.source.getName() + ".original"); workingSource.delete(); renameFile(this.source, workingSource); } destination.delete(); try { //将源jar变成JarFile JarFile jarFileSource = new JarFile(workingSource); try { repackage(jarFileSource, destination, libraries, launchScript); } finally { jarFileSource.close(); } } finally { if (!this.backupSource && !this.source.equals(workingSource)) { deleteFile(workingSource); } } }
这一步所做的是清理工作,如果源jar同目标文件路径名称等一致,将源jar重命名,原来的文件删除。为目标文件腾位置。下面的重点来了。
private void repackage(JarFile sourceJar, File destination, Libraries libraries, LaunchScript launchScript) throws IOException { JarWriter writer = new JarWriter(destination, launchScript); try { final List<Library> unpackLibraries = new ArrayList<Library>(); final List<Library> standardLibraries = new ArrayList<Library>(); libraries.doWithLibraries(new LibraryCallback() { @Override public void library(Library library) throws IOException { File file = library.getFile(); if (isZip(file)) { if (library.isUnpackRequired()) { unpackLibraries.add(library); } else { standardLibraries.add(library); } } } }); //按照规则写入manifest文件 writer.writeManifest(buildManifest(sourceJar)); Set<String> seen = new HashSet<String>(); writeNestedLibraries(unpackLibraries, seen, writer); //写入源jar中的内容 writer.writeEntries(sourceJar); //写入标准的jar,依赖的jar writeNestedLibraries(standardLibraries, seen, writer); if (this.layout.isExecutable()) { //写入spring boot loader的类 writer.writeLoaderClasses(); } } finally { try { writer.close(); } catch (Exception ex) { // Ignore } }
SpringBoot入门之spring-boot-maven-plugin
标签:入门 addition standard out ret rip 生命周期 war dir
原文地址:https://www.cnblogs.com/zouhong/p/12189319.html