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)的轻量级代替品.无 ...
随机推荐
- (转)spring AOP探索
原文地址:http://www.cnblogs.com/zuoxiaolong/p/spring6.html 自己整理后,供自己学习方便: 目前由AOP联盟给出了AOP的标准,AOP联盟的规范只是提供 ...
- BZOJ2431 HAOI2009 逆序对数列 【DP】*
BZOJ2431 HAOI2009 逆序对数列 Description 对于一个数列ai{a_i}ai,如果有i<j且ai>aja_i>a_jai>aj,那么我们称aia ...
- PageViewController和UIPageControl
以前经常把这两个东西当成一回事, PageViewController像电子书那样,一页之中可以放几个childViewcontroller, 然后左右翻,当前frame显示几个viewcontro ...
- vmware linux nat模式设置静态ip
网上资料很多,但是都不怎么实用,这里给大家总结一下.nat模式上网.因为nat本身就能上网为什么还要设置ip.这有点自找麻烦.但是在集群这是必须的.要么你搭建伪分布,要么至少具有三台物理机器.为了节省 ...
- MySQL 字段基本操作
MySQL添加字段的方法并不复杂,下面将为您详细介绍MySQL添加字段和修改字段等操作的实现方法,希望对您学习MySQL添加字段方面会有所帮助. .登录数据库 >mysql -u root -p ...
- spring事务的配置
前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识.通过这次的学习发觉Spring的事务配置只要把思路理清,还是比较好掌握的. ...
- Python中super()和__init__()方法
采用新式类,要求最顶层的父类一定要继承于object,这样就可以利用super()函数来调用父类的init()等函数, 每个父类都执行且执行一次,并不会出现重复调用的情况.而且在子类的实现中,不用到处 ...
- apache phoenix 安装试用
备注: 本次安装是在hbase docker 镜像的基础上配置的,主要是为了方便学习,而hbase搭建有觉得 有点费事,用镜像简单. 1. hbase 镜像 docker pull har ...
- 常用ETL工具
一 ETL工具[国外] 1. datastage点评:最专业的ETL工具,价格不菲,使用难度一般 下载地址:ftp://ftp.seu.edu.cn/Pub/Develop ... taStage.v ...
- Promise的一些相关讲解
在javascrpit的语言特性上 有明确的一个特性指出,该语言的是单线程进程.这就意味着JavaScript的所有网络操作,浏览器事件,都必须是异步执行. 如下面的例子,可以感受到单线程与异步回调: ...