maven-compiler-plugin 与spring-boot-maven-plugin 区别
spring boot中打包插件spring-boot-maven-plugin和maven-jar-plugin的关联
用spring boot快速开发时,通常用spring-boot-maven-plugin插件将springboot的应用程序打包成jar文件,然后通过java -jar运行,很方便。但是如果是部署到服务器上,每次更改代码后替换的包都比较大,至少30MB以上,依赖jar多的甚至超过100MB,传输效率就降低了,其实真正的代码jar是很小的,所以要想办法给jar瘦身。
一、maven-jar-plugin
maven-jar-plugin是jar包生成插件,提供了manifest的配置,生成jar包中一般存放的是.class文件已经resources目录下的东西,文件很小。
二、spring-boot-maven-plugin
从官网的介绍来看,spring-boot-maven-plugin主要目标是spring-boot的启动、停止、运行和repackage,对于打包来说那就是repackage,也就是说它实现的打包功能是重新打包,原始jar包还是由maven-jar-plugin生成的。
spring-boot-maven-plugin
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
maven-compiler-plugin
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
maven-jar-plugin和spring-boot-maven-plugin打包生成的文件
简介
用spring boot快速开发时,通常用spring-boot-maven-plugin插件将springboot的应用程序打包成jar文件,然后通过java -jar运行,很方便。但是如果是部署到服务器上,每次更改代码后替换的包都比较大,至少30MB以上,依赖jar多的甚至超过100MB,传输效率就降低了,其实真正的代码jar是很小的,所以要想办法给jar瘦身。
一、maven-jar-plugin
maven-jar-plugin是jar包生成插件,提供了manifest的配置,生成jar包中一般存放的是.class文件已经resources目录下的东西,文件很小。
二、spring-boot-maven-plugin
从官网的介绍来看,spring-boot-maven-plugin主要目标是spring-boot的启动、停止、运行和repackage,对于打包来说那就是repackage,也就是说它实现的打包功能是重新打包,原始jar包还是由maven-jar-plugin生成的。
三、区别和联系
我们将普通插件maven-jar-plugin生成的包和spring-boot-maven-plugin生成的包进行比较,发现使用spring-boot-maven-plugin生成的jar中主要增加了两部分,第一部分是lib目录,这里存放的是应用的Maven依赖的jar包文件,第二部分是spring boot loader相关的类,所以通常spring-boot-maven-plugin插件打的jar包程为fatjar或者胖jar。
四、总结
所以如果是用部署到生产或者服务器环境最好通过maven-jar-plugin打包,初次打包可以结合maven-assembly-plugin打成压缩文件,以后只需要传送更改的代即可。
转载地址:https://www.jianshu.com/p/19b9634ab412
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。
maven-compiler-plugin 插件详解-CSDN博客
maven 是个管理工具,如果我们不告诉它我们的代码要使用什么样的 jdk 版本编译的话,它就会用 maven-compiler-plugin 默认的 jdk 版本来进行处理,这样就容易出现版本不匹配,以至于可能导致编译不通过的问题。
maven 的默认编译使用的 jdk 版本有时候不通用,使用 maven-compiler-plugin 插件可以指定项目源码的 jdk 版本,编译后的 jdk 版本,以及编码。
maven-compiler-plugin
maven-compiler-plugin 插件是一个 Maven 插件,用来编译项目代码;自从3.0开始默认的编译器是 javax.tools.JavaCompiler,用来编译 Java 源码;如果你想强制插件使用 javac 编译器,你必须配置插件的属性 forceJavacCompilerUse;还要注意,当前默认源(source)设置为 1.6,默认目标(target)设置为 1.6。独立运行 Maven 和 JDK,可以通过 source 和 target 选项更改他们的默认值;
1. maven-compiler-plugin插件当前最高版本是3.8.0下载地址:http://mvnrepository.com/artifact/org.apache.maven.plugins/maven-compiler-plugin
2. 插件设置的各种参数信息请查看
http://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html#forceJavacCompilerUse
-
<build>
-
<plugins>
-
<plugin>
-
<groupId>org.apache.maven.plugins</groupId>
-
<artifactId>maven-compiler-plugin</artifactId>
-
<version>3.8.0</version>
-
<configuration>
-
<source>1.8</source>
-
<target>1.8</target>
-
<encoding>UTF-8</encoding>
-
</configuration>
-
</plugin>
-
</plugins>
-
</build>
-
<plugin>
-
<!-- 指定maven编译的jdk版本,如果不指定,maven3默认用jdk 1.5 maven2默认用jdk1.3 -->
-
<groupId>org.apache.maven.plugins</groupId>
-
<artifactId>maven-compiler-plugin</artifactId>
-
<version>3.1</version>
-
<configuration>
-
<!-- 一般而言,target与source是保持一致的,但是,有时候为了让程序能在其他版本的jdk中运行(对于低版本目标jdk,源代码中不能使用低版本jdk中不支持的语法),会存在target不同于source的情况 -->
-
<source>1.8</source> <!-- 源代码使用的JDK版本 -->
-
<target>1.8</target> <!-- 需要生成的目标class文件的编译版本 -->
-
<encoding>UTF-8</encoding><!-- 字符集编码 -->
-
<skipTests>true</skipTests><!-- 跳过测试 -->
-
<verbose>true</verbose>
-
<showWarnings>true</showWarnings>
-
<fork>true</fork><!-- 要使compilerVersion标签生效,还需要将fork设为true,用于明确表示编译版本配置的可用 -->
-
<executable><!-- path-to-javac --></executable><!-- 使用指定的javac命令,例如:<executable>${JAVA_1_4_HOME}/bin/javac</executable> -->
-
<compilerVersion>1.3</compilerVersion><!-- 指定插件将使用的编译器的版本 -->
-
<meminitial>128m</meminitial><!-- 编译器使用的初始内存 -->
-
<maxmem>512m</maxmem><!-- 编译器使用的最大内存 -->
-
<compilerArgument>-verbose -bootclasspath ${java.home}\lib\rt.jar</compilerArgument><!-- 这个选项用来传递编译器自身不包含但是却支持的参数选项 -->
-
</configuration>
-
</plugin>
Maven之pom.xml继承父pom.xml配置,如何移除父pom中的依赖_maven排除父类pom中的引用的jar-CSDN博客
前言
maven是java项目的管理和构建工具。我们可以通过引入不同依赖,以满足项目开发。项目越大,引入的依赖就越多,带来的管理问题也就越来越突出。
因此,统一的依赖管理就显得尤为重要!
提示:以下是本篇文章正文内容,下面案例可供参考
一、项目间的依赖关系
示例:
二、使用步骤
1.父pom
使用dependencyManagement 和 pluginManagement ,声明子类POM中可能用到的依赖和插件,但并不会引入实际的依赖,或造成实际的插件调用行为,但能够约束子类POM中的依赖和插件配置的声明。
代码如下(示例):
<modelVersion>4.0.0</modelVersion>
<groupId>com.tomandersen</groupId>
<artifactId>HadoopCustomModules</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<!--模块名称-->
<modules>
<module>flume</module>
<module>log-collector</module>
</modules>
<!--事先声明版本属性-->
<properties>
<slf4j.version>1.7.20</slf4j.version>
<logback.version>1.0.7</logback.version>
</properties>
<!--在父类Maven中使用dependencyManagement声明依赖便于子类Module继承使用,也便于进行依赖版本控制-->
<dependencyManagement>
<dependencies>
<!--阿里巴巴开源json解析框架-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.51</version>
</dependency>
<!--日志生成框架-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<!--在父类Maven中使用pluginManagement管理插件便于子类Module继承使用,也便于进行依赖版本控制-->
<pluginManagement>
<plugins>
<!--配置Maven项目compiler插件-->
<!--此工具不会打包依赖-->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!--配置Maven项目assembly插件-->
<!--此工具会将全部依赖打包-->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<!--子类Maven通过mainClass标签设置成主类的全类名FQCN-->
<!--<mainClass></mainClass>-->
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
2.子POM
1)在子类POM中声明父类POM
2)配置实际使用的 dependency 和 plugin,只需要声明 groupId 和 artifactId 就可以,只有声明的才会进行实际的依赖引入或插件调用
3)版本在父POM中统一管理,不用指定版本。指定版本,则覆盖父类配置信息
代码如下(示例):
<!--声明父类POM-->
<parent>
<artifactId>HadoopCustomModules</artifactId>
<groupId>com.tomandersen</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<!--子类POM信息-->
<groupId>com.tomandersen</groupId>
<artifactId>log-collector</artifactId>
<dependencies>
<!--阿里巴巴开源json解析框架-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<!--日志生成框架-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<!--如果不配置,则不会引进父pom中的依赖-->
<!-- <dependency>-->
<!-- <groupId>ch.qos.logback</groupId>-->
<!-- <artifactId>logback-classic</artifactId>-->
<!-- </dependency>-->
</dependencies>
<build>
<plugins>
<!--自定义Maven项目编译器compiler插件相关配置-->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<!--自定义Maven项目汇编assembly插件相关配置-->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<!--此处设置成主类的全名-->
<mainClass>com.tomandersen.appclient.AppMain</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。
三、重复依赖,依赖冲突
由于一些dependency中包含了某个jar,然后我们又导入了其他jar,不知不觉中造成jar冲突,或者是重复依赖……这样整个项目的jar就会越来越冗余,庞大
方法一:把父pom依赖的jar包排除掉
-
如何查看依赖树图
-
放大后,会看到一些红线,这就是冲突的jar。一般选择低版本的depedency,点击右键——Exclude
去除了冲突或者重复的jar,maven会在对应pom的depedency中加 <exclusions>用于去掉某个依赖里的jar。
方法一:把父pom依赖的jar包覆盖掉
举例:
假如我们在项目pom中引入一个统一的依赖管理项目。
在common-base中引入了
但是我们想在datasource中使用最新版本的依赖,可以直接在datasource的pom中指定版本。
这样就可以使用最新的版本了。
但是,在依赖树图中,我们会看到又多了一条红线。也就意味着可能存在冲突。
重点、重点、重点、
########################################
产生冲突的原因,是因为根据 maven依赖最短路径原则,必然是产生了两个 相同路径长度 的依赖,版本不一致导致的。
########################################
强调一下,树图的红线并不影响项目的正常运行和打包,maven打包时会按照最短路径把需要的jar打包。
所以,只要再定义一个更短路径的依赖就可以解决。
比如我打的包时start,只要在start模块的pom中再引入一次依赖,就可以解决冲突ClassNotFoundException的问题。
maven删除不必要的依赖;优化pom依赖研究_没用的maven依赖-CSDN博客
maven如何去除没有使用的依赖:
项目做了比较大的改动。
以前很多的依赖都没有用了。
能否让maven或者eclipse自动检索,哪些依赖是没有被使用的。标记出来或者直接删除。
方法1:
好像没有这个功能。你可以手动筛选。把不是必须的包配置注释掉。如果报异常,就把需要的包的注释打开。
方法2:
>mvn dependency:analyze
[INFO] --- maven-dependency-plugin:2.8:analyze (default-cli) @ wtp-core ---
[WARNING] Used undeclared dependencies found:
[WARNING] org.springframework:spring-beans:jar:3.2.3.RELEASE:compile
[WARNING] Unused declared dependencies found:
[WARNING] junit:junit:jar:4.7:test
[WARNING] org.springframework:spring-test:jar:3.2.3.RELEASE:test
[WARNING] org.slf4j:jcl-over-slf4j:jar:1.6.1:runtime
[WARNING] org.slf4j:slf4j-log4j12:jar:1.6.1:runtime
[WARNING] commons-lang:commons-lang:jar:2.5:test
方法3:
可以用 查看项目依赖:mvn dependency:analyze; 或 mvn dependency:analyze -DignoreNonCompile
查看项目直接和传递依赖:mvn dependency:tree ;
查看maven构建时有效的pom:mvn help:effective-pom 来看哪些jar是不需要的,再排除就好了。