SpringBoot入门之spring-boot-maven-plugin
spring-boot-maven-plugin插件是将springboot的应用程序打包成fat jar的插件。首先我们说一下啥叫fat jar。fat jar 我们暂且叫他胖jar吧,实在是找不到官方叫法了。我们一般的jar,里面放的是.class文件已经resources目录下的东西,但是fat jar 它可以把jar作为内容包含进去。也就是说,spring boot 借助spring-boot-maven-plugin将所有应用启动运行所需要的jar都包含进来,从逻辑上将具备了独立运行的条件。
我们将普通插件maven-jar-plugin生成的包和spring-boot-maven-plugin生成的包unzip,比较一下他们直接的区别,发现使用spring-boot-maven-plugin生成的jar中主要增加了两部分,第一部分是lib目录,这里存放的是应用的Maven依赖的jar包文件,第二部分是spring boot loader相关的类,这个我们下一节再说spring boot 的加载流程。
在项目中需要先加入spring-boot-maven-plugin。
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.3.2.RELEASE</version>
<configuration>
<mainClass>test.ApplicationMain</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
默认是在package阶段执行spring-boot-maven-plugin repackage这个目标。我们看一下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
}
}
}
上面就是一通写,将所需要的内容全部写入到目标文件中。然后就有了我们的fat jar。
作者:数齐
链接:https://www.jianshu.com/p/19b9634ab412
SpringBoot入门之spring-boot-maven-plugin的更多相关文章
- Spring Boot的Maven插件Spring Boot Maven plugin详解
Spring Boot的Maven插件(Spring Boot Maven plugin)能够以Maven的方式为应用提供Spring Boot的支持,即为Spring Boot应用提供了执行Mave ...
- Spring Boot Maven Plugin(二):run目标
简介 Spring Boot Maven Plugin插件提供spring boot在maven中的支持.允许你打包可运行的jar包或war包. 插件提供了几个maven目标和Spring Boot ...
- Spring Boot Maven Plugin(一):repackage目标
简介 Spring Boot Maven Plugin插件提供spring boot在maven中的支持.允许你打包可运行的jar包或war包. 插件提供了几个maven目标和Spring Boot ...
- Spring Boot Maven Plugin打包异常及三种解决方法:Unable to find main class
[背景]spring-boot项目,打包成可执行jar,项目内有两个带有main方法的类并且都使用了@SpringBootApplication注解(或者另一种情形:你有两个main方法并且所在类都没 ...
- spring boot入门教程——Spring Boot快速入门指南
Spring Boot已成为当今最流行的微服务开发框架,本文是如何使用Spring Boot快速开始Web微服务开发的指南,我们将使创建一个可运行的包含内嵌Web容器(默认使用的是Tomcat)的可运 ...
- 微服务下 Spring Boot Maven 工程依赖关系管理
单体 Spring Boot Maven 工程 最基本的 pom.xml 包含工程信息.Spring Boot 父工程.属性配置.依赖包.构建插件 <?xml version="1.0 ...
- Kafka 入门和 Spring Boot 集成
目录 Kafka 入门和 Spring Boot 集成 标签:博客 概述 应用场景 基本概念 基本结构 和Spring Boot 集成 集成概述 集成环境 kafka 环境搭建 Spring Boot ...
- 图书-技术-SpringBoot:《Spring Boot 企业级应用开发实战》
ylbtech-图书-技术-SpringBoot:<Spring Boot 企业级应用开发实战> Spring Boot 企业级应用开发实战,全书围绕如何整合以 Spring Boot 为 ...
- spring boot学习总结(一)-- 基础入门 Hello,spring boot!
写在最前 SpringBoot是伴随着Spring4.0诞生的: 从字面理解,Boot是引导的意思,因此SpringBoot帮助开发者快速搭建Spring框架: SpringBoot帮助开发者快速启动 ...
- Spring Boot入门 and Spring Boot与ActiveMQ整合
1.Spring Boot入门 1.1什么是Spring Boot Spring 诞生时是 Java 企业版(Java Enterprise Edition,JEE,也称 J2EE)的轻量级代替品.无 ...
随机推荐
- yum源笔记
1. epel源,使用yum安装htop http://download.fedoraproject.org/pub/epel/5/i386/epel-release-5-4.noarch.rpm 2 ...
- Failed to read schema document
转自:http://eric-yan.iteye.com/blog/1908470 问题描述: web项目web.xml编译错误: schema_reference.4: Failed to read ...
- BZOJ5142: [Usaco2017 Dec]Haybale Feast(双指针&set)(可线段树优化)
5142: [Usaco2017 Dec]Haybale Feast Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 182 Solved: 131[ ...
- Codeforces 17E Palisection 【Manacher】
Codeforces 17E Palisection E. Palisection In an English class Nick had nothing to do at all, and rem ...
- functool.wraps and functools.partial
functools.partial 通过包装手法,允许我们 "重新定义" 函数签名. 通常是将函数的部分参数给固定下来, 从而形成一个输入参数更少的新函数. functool.w ...
- js动态的属性名如何取该属性的值
var cls={cn1:"nihao",cn2="made",cn3="shuide"};var index=2;//可变获取cn2的值 ...
- python 读取Linux服务器上的文件
使用Python语句,读取Linux远端服务器上的文件打印到控制台的代码实现: 下载包:paramiko import paramiko #服务器信息,主机名(IP地址).端口号.用户名及密码 hos ...
- 使用JDK合成照片
原图(工程所在目录7098849.jpg): 头像(工程所在目录20181023201750.jpg): 开始合成(执行如下main方法): public static void main(Strin ...
- zk中文乱码问题
之前讲了怎么把数据导入到zookeeper(见zookeeper事件监听的importData方法),虽然本机win10的zookeeper展示没问题,但到了linux上就出现乱码了: << ...
- Linux 准确查找结构体定义位置
例如:查找文件操作结构体 struct file_operations, 使用转移符 "\" $ grep struct\ file_operations\ { kernel/in ...