1. 常用命令备忘
打包 package 或安装 install 时,跳过失败的单元测试类UT的命令行:
mvn install -Dmaven.test.skip=true
或者mvn install -DskipTests=true
或者是给surefire插件增加参数:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
在 maven 工程里运行 java main方法:
mvn exec:java -Dexec.mainClass="demo.Main"
离线构建:用于断开互联网连接但仍需构建工程的情况下,可以在命令行中使用离线开关:
mvn -o package
许多插件会判断离线设置而不去连接互联网,比如解析Javadoc链接和网站的链接检查。
packaging:打包格式,可选值:jar(默认值), maven-plugin, ejb, war, ear, rar, par。
将下载或者从其他路径得到的,但是在maven repository找不到artifactId信息的jar包安装到本地仓库的命令,然后就可以通过使用maven的pom文件来管理,而不是最传统的配置classpath的方法:
mvn install:install-file -Dfile=neuroph-2.6.jar -DgroupId=org.neuroph -DartifactId=neuroph -Dversion=2.6 -Dpackaging=jar
注意需要在 jar 包的目录下面执行这个命令。
项目需要使用 jmx 库,但是因为 sun 的 license 限制,所以无法将其直接包含在repository中。如果想把它安装到公司的repository中的命令:
mvn deploy:deploy-file -DgroupId=com.sun.jdmk -DartifactId=jmxtools -Dversion=1.2.1 -Dpackaging=jar -Dfile=/path/to/file -Durl=http://xxx.ss.com/sss.xxx -DrepositoryId=release-repo
2. maven-assembly-plugin
在一个Linux环境下使用maven-assembly-plugin插件,前期使用得很正常,后来报错:
Failed to execute goal org.apache.maven.plugins:maven-assembly-plugin:2.6:single (make-assembly) on project suite-demo-config-web: Execution make-assembly of goal org.apache.maven.plugins:maven-assembly-plugin:2.6:single failed: user id '3518522' is too big ( > 2097151 ). -> [Help 1]
经过排查,发现问题是版本导致的,将目前使用的版本由2.6降到2.4,解决问题,深层原因暂时未知。
参考链接:https://stackoverflow.com/questions/33943565/error-with-maven-build-with-assembly-plugin
3.wagon-maven-plugin
在pom.xml文件里面的<build>
里面配置:
<extensions>
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh</artifactId>
<version>2.8</version>
</extension>
</extensions>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>wagon-maven-plugin</artifactId>
<version>1.0</version>
<configuration>
<serverId>15.119.81.111</serverId>
<fromFile>target/extractor-alm.jar</fromFile>
<url>
scp://hpba@15.119.81.111/home/hpba/HPBA-340-340-master-redhat-x64/ContentPacks/ALM/EXTRACTOR/extractor-alm/
</url>
</configuration>
</plugin>
同时在maven的setting.xml文件里面配置server信息(用户名和密码)
实现jar/war包自动上传到server,部署。
4. maven classifier 的作用
一般情况下,在 pom 文件引入某个 dependency 时指定<groupId>、<artifactId>、<version>
即可,但是在使用json-lib,mvn.repository.com查找它的dependency时结果如下:
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
</dependency>
然而import时提示无法找到这个jar。
原因是:json-lib提供两个jdk版本的实现, json-lib-2.1-jdk13.jar和json-lib-2.1-jdk15.jar。
解决办法,在dependency 标签里面添加classifier
:
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
即添加json-lib-2.4-jdk15.jar。classifier用于区分名字相同但内容不同的POM。例如:jdk15和jdk14指明目标版本;sources和javadoc指明部署的是源码还是文档。
5.docker-maven-plugin
在使用spotify的docker-maven-plugin遇到的一个问题。
Linux环境下配置好docker-maven-plugin插件的maven pom文件,前期使用完全没有问题,后来执行mvn clean install遇到报错:
Retrying request to {}->unix://localhost:80
...
Failed to execute goal com.spotify:docker-maven-plugin:0.4.13:build (build-image) on project demo-suite-data-image: Exception caught: java.util.concurrent.ExecutionException: com.spotify.docker.client.shaded.javax.ws.rs.ProcessingException: java.io.IOException: No such file or directory –
初始时,把报错信息的焦点定位于ProcessingException以及No such file or directory,当然google不懂任何有用的信息。
换个思路,google Retrying request to {}->unix://localhost:80。
找到参考:https://github.com/spotify/docker-maven-plugin/issues/105
总结起来就是,你现在的Linux坏境docker已经出问题,maven插件需要借助于docker环境(如docker daemon等) ;docker verion或者docker info提示有错,maven当然会执行失败。
6.maven-assembly-plugin
使用maven的assembly插件时遇到的一个问题。
需求场景是:把web工程mvn clean install生成的war包放置到下载之后的JBoss压缩包解压缩之后的文件夹deployment/standalone下面,替换里面的已有war包,重新打包成tar.gz格式的压缩包供后面的dockerfile使用。pom.xml及assembly.xml文件一切配置就绪。
前期使用也是正常,几次之后出问题,报错:
[WARNING] Entry: hpas-7.4.3/bundles/system/layers/base/javax/servlet/api/v25/jboss-servlet-api_2.5_spec-1.0.1.Final.jar longer than 100 characters.
网上有很多类似的故障如:http://stackoverflow.com/questions/9416511/tycho-shots-a-warning-when-my-entry-is-longer-than-100-chars
各种google之后,解决方法有两类:
1.不用这个assembly插件,换一个更强大的tycho-p2-director-plugin[http://git.eclipse.org/c/tycho/org.eclipse.tycho.git/] ,但是需要重新学习了解的成本。
2.更新maven的插件版本,从现有的2.6之后升级到3.0.0,但是:
貌似很多时候,maven的插件报错不影响其功能使用。
但是,这都不是完美的解决方案。
终于找到一个更靠谱的解决方法:
https://github.com/downgoon/memcloud/issues/4
在< plugin>——<execution>——<configuration>
下面配置
<tarLongFileMode>gnu</tarLongFileMode>
7. Eclipse导入maven项目报错:could not read pom.xml
如图,IDE是Eclipse,导入GitHub上面git clone的maven项目时,报错:
参考
意思是pom.xml有不能解析的配置项,把不能解析的配置修改过来即可。
与其他pom文件对比,发现多了这一行:
<?xml version=”1.0″ encoding=”UTF-8″?>
去掉就行。wait but why?git clone的maven项目,怎么会有这种问题呢?还是一个高star的项目。
8. Eclipse解析pom.xml文件报错
报错信息如此:
Plugin execution not covered by lifecycle configuration with:org.jvnet.maven-antrun-extended-plugin:maven-antrun-extended-plugin:1.43:run(execution: unpack, phase: compile)
具体是配置和GWT相关。
参考:
http://stackoverflow.com/questions/14886380/generated-project-with-gwt-maven-plugin-eclipse
http://stackoverflow.com/questions/8523737/why-am-i-receiving-a-plugin-execution-not-covered-by-lifecycle-configuration-wi
如图所示大致解决方法:
- 第一种会改变pom.xml文件,生产代码,不推荐提交更改;
- 更改自己本地开发坏境的配置,即将修改置于settings directory,建议。
9. maven-resources-plugin的使用
直入主题:
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>docker</outputDirectory>
<outputDirectory>kubernetes</outputDirectory>
<resources>
<resource>
<directory>target</directory>
<includes>
<include>*.jar</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
如上配置,只有最后一个outputDirectory是有效的,即只把target下面的jar文件copy到kubernetes,并没有copy到上一个配置的outputDirectory,即docker。
那配置两个maven-resources-plugin?如下所示:
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>kubernetes</outputDirectory>
<resources>
<resource>
<directory>target</directory>
<includes>
<include>*.jar</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>docker</outputDirectory>
<resources>
<resource>
<directory>target</directory>
<includes>
<include>*.jar</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
也是只有下面一个配置项生效。
10. 关于 maven scope
1.Compile(编译)
compile,默认值。编译范围依赖在所有的classpath中可用,同时它们也会被打包。依赖的传递性只在compile范围进行。
2.Provided(已提供)
provided依赖只有在当JDK或者一个容器已提供该依赖之后才使用。例如,如果你开发一个web应用,你可能在编译classpath中需要可用的Servlet API来编译一个servlet,但是你不会想要在打包好的WAR中包含这个Servlet API;这个Servlet API JAR由你的应用服务器或者servlet容器提供。已提供范围的依赖在编译classpath(不是运行时)可用。它们不是传递性的,也不会被打包。
3.Runtime(运行时)
runtime依赖在运行和测试系统的时候需要,但在编译的时候不需要。比如,你可能在编译的时候只需要JDBC API JAR,而只有在运行的时候才需要JDBC驱动实现。
4.Test(测试)
Test范围依赖 在一般的 编译和运行时都不需要,它们只有在测试编译和测试运行阶段可用。
5.System(系统)
system范围依赖与provided类似,但是必须显式的提供一个对于本地系统中JAR文件的路径。与本机系统相关联,可移植性差。这么做是为了允许基于本地对象编译,而这些对象是系统类库的一部分。这样的构件应该是一直可用的,Maven也不会在仓库中去寻找它。如果你将一个依赖范围设置成系统范围,你必须同时提供一个systemPath元素。注意该范围是不推荐使用的(你应该一直尽量去从公共或定制的Maven仓库中引用依赖)。
6. import(导入):
只使用在dependencyManagement中,表示从其它的pom中导入dependency的配置。
下面重点讲解compile 和 provided区别
对于scope=compile的情况(默认scope),也就是说这个项目在编译,测试,运行阶段都需要这个artifact对应的jar包在classpath中。
而对于scope=provided的情况,则可以认为这个provided是目标容器已经provide这个artifact。换句话说,它只影响到编译,测试阶段。在编译测试阶段,需要这个artifact对应的jar包在classpath中,而在运行阶段,假定目标的容器(如tomcat、jboss)已经提供这个jar包,所以无需这个artifact对应的jar包。
实际插件的行为:
用maven install生成最终的构件包demo.war后,在其下的WEB-INF/lib中,会包含被标注为scope=compile的构件的jar包,而不会包含被标注为scope=provided的构件的jar包。这也避免此类构件当部署到目标容器后产生包依赖冲突。
11. Maven 环境变量
在将近三年的java开发生涯,maven环境变量的配置进行不少次,有说M2_HOME,有说MAVEN_HOME,但是一直搞不清楚两者有什么区别?知道最近在搭建.NET开发环境的时候,安装一个.NET 工程转maven工程的插件NPanday时才知道,两者并存的情况下,M2_HOME的优先级更高。
两者并存时输入命令:mvn -v:
12. mvn clean 报错 Unknown host
执行无数次的mvn clean
竟然报错:
Plugin org.apache.maven.plugins:maven-clean-plugin:2.5 or one of its dependencies could not be resolved: Failed to read artifact descriptor for org.apache.maven.plugins:maven-clean-plugin:jar
:2.5: Could not transfer artifact org.apache.maven.plugins:maven-clean-plugin:pom:2.5 from/to nexus (http://maven.release.johnnycorp.com/nexus/content/groups/public): maven.dev.sh.johnnycorp.com: Unknown host maven.dev.sh.johnnycorp.com。hostname做了替换!
命令行:ping maven.dev.sh.johnnycorp.com
报错:
Ping 请求找不到主机 maven.dev.sh.johnnycorp.com。请检查该名称,然后重试。
但是使用右侧的maven projects面板,lifecycle 选择clean,双击,则没有问题!!!哪里来的这个莫名其妙的hostname??只可能是maven 的settings.xml,在内网的 confluence wiki 搜索到另外一个settings.xml配置文件;
对比一下现在使用的,没有什么差别!!但是替换之后就没有问题!!
13. maven解析依赖出错
问题背景:公司配置的Win 10系统,由于一些权限上的问题,会找IT帮忙解决,于是在本地磁盘留下用户信息:
如图,加码的是我的个人用户名信息,下面的lpxie是IT人员在操作我的电脑时留下的用户信息。
现在想要在本地安装jar包,用
mvn install:install-file -Dfile=jbarcode-0.2.8.jar -DgroupId=org.jbarcode -DartifactId=jbarcode -Dversion=0.2.8 -Dpackaging=jar
命令没有任何问题,打印输出: BUILD SUCCESS。
但是IDEA还是出现解析依赖出错的红色提示。纳了闷,于是去本地仓库,也就是上面的打码的user下面的.m2文件夹找,但是并没有找到jar包。那肯定就解析失败啊。此时才注意到上面这个命令行的输出信息是
Installing D:\Users\jian.wang\AppData\Local\Temp\mvninstall5508834578350192072.pom to d:\Users\lpxie\.m2\repository\org\jbarcode\jbarcode\0.2.8\jbarcode-0.2.8.pom
可见,并没有安装到我期望的用户下面去,而是安装到另一个用户下面去。
明白这个之后,解决方法那就简单,在maven的settings.xml文件里面hard code一个绝对路径:
<localRepository>D:\Users\j***ng\.m2\repository</localRepository>
但是为什么maven会把user信息识别出错呢???而且我删除那个用户文件夹,重启电脑,都不行,为什么???不知道啊!!!
14. mvn install [ERROR]java.lang.OutOfMemoryError: PermGen space”
在编译工程时,内存不够。
解决方法1:
设定环境变量:set MAVEN_OPTS=-Xmx512m -XX:MaxPermSize=128m
解决方法2:
If you want to make this part of your POM for a repeatable build, you can use the fork-variant of a few of the plugins (especially compiler:compile and surefire:test):
意思是如果你的pom文件有配置compiler插件,可以进一步配置<configuration>
属性,如compiler 和 surefire:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<fork>true</fork>
<meminitial>128m</meminitial>
<maxmem>1024m</maxmem>
<compilerArgs>
<arg>-XX:MaxPermSize=256m</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18</version>
<configuration>
<forkCount>1</forkCount>
<argLine>-Xmx1024m -XX:MaxPermSize=256m</argLine>
</configuration>
</plugin>
15. 添加非官方repository
虽然maven的官方仓库repository现在已经有11.0M(即1千1百万)个artifactId,但是在我们的日常开发中,还是会遇到在maven的官方仓库找不到所需的gav,但是在非官方repository(比如Jboss)可以找到,此时可以通过配置第三方的repository把jar包下载到本地。
方法:
打开.m2/settings.xml
文件,添加:
<profiles>
<profile>
<id>jboss</id>
<repositories>
<repository>
<id>jboss-public-repository-group</id>
<name>JBoss Public Maven Repository Group</name>
<url>https://repository.jboss.org/nexus/content/repositories/releases</url>
<layout>default</layout>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
<updatePolicy>never</updatePolicy>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>jboss</id>
<name>jboss</name>
<releases>
<enabled>false</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
<checksumPolicy>fail</checksumPolicy>
</snapshots>
<url>https://repository.jboss.org/nexus/content/repositories/releases</url>
<layout>default</layout>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
即可。更改默认的 maven 的仓库,需在 pom.xml 文件中添加设置(如有私服须放置在前面)。
16. 常用 Maven 插件介绍
Maven本质上是一个插件框架,它的核心并不执行任何具体的构建任务,所有这些任务都交给插件来完成。进一步说,每个任务对应一个插件目标(goal),每个插件会有一个或者多个目标。
用户可以通过两种方式调用Maven插件目标。第一种方式是将插件目标与生命周期阶段(lifecycle phase)绑定,这样用户在命令行只是输入生命周期阶段而已,例如Maven默认将maven-compiler-plugin的compile目标与 compile生命周期阶段绑定,因此命令mvn compile实际上是先定位到compile这一生命周期阶段,然后再根据绑定关系调用maven-compiler-plugin的compile目标。第二种方式是直接在命令行指定要执行的插件目标,例如mvn archetype:generate 就表示调用maven-archetype-plugin的generate目标,这种带冒号的调用方式与生命周期无关。
Maven官方有两个插件列表,第一个列表的GroupId为org.apache.maven.plugins,是为官方插件;第二个列表的GroupId为org.codehaus.mojo。
maven-antrun-plugin
maven-antrun-plugin能让用户在Maven项目中运行Ant任务。用户可以直接在该插件的配置以Ant的方式编写Target, 然后交给该插件的run目标去执行。在一些由Ant往Maven迁移的项目中,该插件尤其有用。此外当你发现需要编写一些自定义程度很高的任务,同时又觉 得Maven不够灵活时,也可以以Ant的方式实现之。maven-antrun-plugin的run目标通常与生命周期绑定运行。
maven-archetype-plugin
Archtype指项目的骨架,Maven初学者最开始执行的Maven命令可能就是mvn archetype:generate,这实际上就是让maven-archetype-plugin生成一个很简单的项目骨架,帮助开发者快速上手。可能也有人看到一些文档写了mvn archetype:create, 但实际上create目标已经被弃用了,取而代之的是generate目标,该目标使用交互式的方式提示用户输入必要的信息以创建项目,体验更好。 maven-archetype-plugin还有一些其他目标帮助用户自己定义项目原型,例如你由一个产品需要交付给很多客户进行二次开发,你就可以为 他们提供一个Archtype,帮助他们快速上手。
maven-assembly-plugin
maven-assembly-plugin的用途是制作项目分发包,该分发包可能包含了项目的可执行文件、源代码、readme、平台脚本等等。 maven-assembly-plugin支持各种主流的格式如zip、tar.gz、jar和war等,具体打包哪些文件是高度可控的,例如用户可以 按文件级别的粒度、文件集级别的粒度、模块级别的粒度、以及依赖级别的粒度控制打包,此外,包含和排除配置也是支持的。maven-assembly- plugin要求用户使用一个名为assembly.xml的元数据文件来表述打包,它的single目标可以直接在命令行调用,也可以被绑定至生命周期。
maven-dependency-plugin
maven-dependency-plugin最大的用途是帮助分析项目依赖,dependency:list能够列出项目最终解析到的依赖列表,dependency:tree能进一步的描绘项目依赖树,dependency:analyze可以告诉你项目依赖潜在的问题,如果你有直接使用到的却未声明的依赖,该目标就会发出警告。maven-dependency-plugin还有很多目标帮助你操作依赖文件,例如dependency:copy-dependencies能将项目依赖从本地Maven仓库复制到某个特定的文件夹下面。
maven-enforcer-plugin
在一个稍大一点的组织或团队中,你无法保证所有成员都熟悉Maven,那他们做一些比较愚蠢的事情就会变得很正常,例如给项目引入了外部的 SNAPSHOT依赖而导致构建不稳定,使用了一个与大家不一致的Maven版本而经常抱怨构建出现诡异问题。maven-enforcer- plugin能够帮助你避免之类问题,它允许你创建一系列规则强制大家遵守,包括设定Java版本、设定Maven版本、禁止某些依赖、禁止 SNAPSHOT依赖。只要在一个父POM配置规则,然后让大家继承,当规则遭到破坏的时候,Maven就会报错。除了标准的规则之外,你还可以扩展该插 件,编写自己的规则。maven-enforcer-plugin的enforce目标负责检查规则,它默认绑定到生命周期的validate阶段。
maven-help-plugin
maven-help-plugin是一个小巧的辅助工具,最简单的help:system可以打印所有可用的环境变量和Java系统属性。help:effective-pom和help:effective-settings最 为有用,它们分别打印项目的有效POM和有效settings,有效POM是指合并了所有父POM(包括Super POM)后的XML,当你不确定POM的某些信息从何而来时,就可以查看有效POM。有效settings同理,特别是当你发现自己配置的 settings.xml没有生效时,就可以用help:effective-settings来验证。此外,maven-help-plugin的describe目标可以帮助你描述任何一个Maven插件的信息,还有all-profiles目标和active-profiles目标帮助查看项目的Profile。
maven-release-plugin
maven-release-plugin,帮助自动化项目版本发布,它依赖于POM中的SCM信息。release:prepare用来准备版本发布,具体的工作包括检查是否有未提交代码、检查是否有SNAPSHOT依赖、升级项目的SNAPSHOT版本至RELEASE版本、为项目打标签等。release:perform则是签出标签中的RELEASE源码,构建并发布。maven-release-plugin的各种目标通常直接在命令行调用,因为版本发布显然不是日常构建生命周期的一部分。
maven-resources-plugin
为了使项目结构更为清晰,Maven区别对待Java代码文件和资源文件,maven-compiler-plugin用来编译Java代码,maven-resources-plugin则用来处理资源文件。默认的主资源文件目录是src/main/resources,很多用户会需要添加额外的资源文件目录,这个时候就可以通过配置maven-resources-plugin来实现。此外,资源文件过滤也是Maven的一大特性,你可以在资源文件中使用${propertyName}形式的Maven属性,然后配置maven-resources-plugin开启对资源文件的过滤,之后就可以针对不同环境通过命令行或者Profile传入属性的值,以实现更为灵活的构建。
maven-surefire-plugin
可能是由于历史的原因,Maven 2/3中用于执行测试的插件不是maven-test-plugin,而是maven-surefire-plugin。其实大部分时间内,只要你的测试 类遵循通用的命令约定(以Test结尾、以TestCase结尾、或者以Test开头),就几乎不用知晓该插件的存在。然而在当你想要跳过测试、排除某些 测试类、或者使用一些TestNG特性的时候,了解maven-surefire-plugin的一些配置选项就很有用了。例如 mvn test -Dtest=FooTest 这样一条命令的效果是仅运行FooTest测试类,这是通过控制maven-surefire-plugin的test参数实现的。
build-helper-maven-plugin
Maven默认只允许指定一个主Java代码目录和一个测试Java代码目录,虽然这其实是个应当尽量遵守的约定,但偶尔你还是会希望能够指定多个 源码目录(例如为了应对遗留项目),build-helper-maven-plugin的add-source目标就是服务于这个目的,通常它被绑定到 默认生命周期的generate-sources阶段以添加额外的源码目录。需要强调的是,这种做法还是不推荐的,因为它破坏了 Maven的约定,而且可能会遇到其他严格遵守约定的插件工具无法正确识别额外的源码目录。
build-helper-maven-plugin的另一个非常有用的目标是attach-artifact,使用该目标你可以以classifier的形式选取部分项目文件生成附属构件,并同时install到本地仓库,也可以deploy到远程仓库。
exec-maven-plugin
exec-maven-plugin很好理解,顾名思义,它能让你运行任何本地的系统程序,在某些特定情况下,运行一个Maven外部的程序可能就是最简单的问题解决方案,这就是exec:exec的 用途,当然,该插件还允许你配置相关的程序运行参数。除了exec目标之外,exec-maven-plugin还提供了一个java目标,该目标要求你 提供一个mainClass参数,然后它能够利用当前项目的依赖作为classpath,在同一个JVM中运行该mainClass。有时候,为了简单的 演示一个命令行Java程序,你可以在POM中配置好exec-maven-plugin的相关运行参数,然后直接在命令运行mvn exec:java 以查看运行效果。
jetty-maven-plugin
在进行Web开发的时候,打开浏览器对应用进行手动的测试几乎是无法避免的,这种测试方法通常就是将项目打包成war文件,然后部署到Web容器 中,再启动容器进行验证,这显然十分耗时。为了帮助开发者节省时间,jetty-maven-plugin应运而生,它完全兼容 Maven项目的目录结构,能够周期性地检查源文件,一旦发现变更后自动更新到内置的Jetty Web容器中。做一些基本配置后(例如Web应用的contextPath和自动扫描变更的时间间隔),你只要执行 mvn jetty:run ,然后在IDE中修改代码,代码经IDE自动编译后产生变更,再由jetty-maven-plugin侦测到后更新至Jetty容器,这时你就可以直接 测试Web页面了。需要注意的是,jetty-maven-plugin并不是宿主于Apache或Codehaus的官方插件,因此使用的时候需要额外 的配置settings.xml的pluginGroups元素,将org.mortbay.jetty这个pluginGroup加入。
versions-maven-plugin
很多Maven用户遇到过这样一个问题,当项目包含大量模块的时候,为他们集体更新版本就变成一件烦人的事情,到底有没有自动化工具能帮助完成这件 事情呢?(当然你可以使用sed之类的文本操作工具,不过不在本文讨论范围)答案是肯定的,versions-maven- plugin提供了很多目标帮助你管理Maven项目的各种版本信息。例如最常用的,命令 mvn versions:set -DnewVersion=1.1-SNAPSHOT 就能帮助你把所有模块的版本更新到1.1-SNAPSHOT。该插件还提供了其他一些很有用的目标,display-dependency- updates能告诉你项目依赖有哪些可用的更新;类似的display-plugin-updates能告诉你可用的插件更新;然后use- latest-versions能自动帮你将所有依赖升级到最新版本。最后,如果你对所做的更改满意,则可以使用 mvn versions:commit 提交,不满意的话也可以使用 mvn versions:revert 进行撤销。
17. maven 变量
maven定义很多变量属性:
- 内置属性
${basedir } represents the directory containing pom.xml
${version } equivalent to ${project.version } or ${pom.version} - Pom/Project properties
所有pom中的元素都可以用 project. 前缀进行引用,部分常用:
${project.build.directory } results in the path to your “target” dir, this is the same as ${pom.project.build.directory }
${project.build. outputD irectory } results in the path to your “target/classes” dir
${project.name } refers to the name of the project.
${project.version } refers to the version of the project.
${project.build.finalName } refers to the final name of the file created when the built project is packaged - 本地用户设定
所有用的的 settings.xml 中的设定都可以通过 settings. 前缀进行引用
${settings.localRepository } refers to the path of the user’s local repository.
${maven.repo.local } also works for backward compatibility with maven2. - 环境变量
系统的环境变量通过 env. 前缀引用
${env.M2_HOME } returns the Maven2 installation path.
${java.home } specifies the path to the current JRE_HOME environment use with relative paths to get for example:
<jvm>${java.home}../bin/java.exe</jvm>
- java系统属性
所有JVM中定义的java系统属性; - 用户在pom中定义的自定义属性
通过在<properties>
里面定义的属性; - 上级工程的变量
上级工程的pom中的变量用前缀 ${project.parent } 引用. 上级工程的版本也可以这样引用: ${parent.version }.
18. 快照版本 snapshot 和正式版本 release
在Nexus仓库中,一个仓库(repository,一个仓库就是一个GAV)一般分为public(Release)仓和SNAPSHOT仓,前者存放正式版本,后者存放快照版本。
两者的主要区别在于,本地获取这些依赖的机制有所不同。假设你依赖一个库的正式版本,构建时构建工具会先在本次仓库中查找是否已经有这个依赖库(即 jar 包),没有的话才会去远程仓库中去拉取。而 snapshot 方式,则是默认每次都去远程仓库检查是否有更新版本的 jar 包,有则下载缓存到本地仓库。
在团队协作中,A 小组依赖于 B 小组提供的一个服务接口 accountService.jar。如果以 release 方式发布到公司内部的 nexus 仓库的话,则 A 小组不能获取到接口的更新。
- 解决方法1:除非手动去本地仓库删除这个 jar,然后重新下载;
- 解决方法2:强制要求小组 B 每次更改 jar 包里面的接口方法时都发布一个新的版本。
无论哪种方式,都会显得很低效。此时就需要使用快照方式去发布版本。
使用 snapshot 方式,每次构建时去内部的远程仓库检查是否有更新版本的 snapshot 快照版本,有则下载;但是这样会显得低效。故而 maven 提供以下机制控制检查快照版本的时间间隔,分别是always、daily、interval、never。当本地仓库中存在需要的依赖项目时,always是每次都去远程仓库查看是否有更新,daily是只在第一次的时候查看是否有更新,当天的其它时候则不会查看;interval允许设置一个分钟为单位的间隔时间,在这个间隔时间内只会去远程仓库中查找一次,never是不会去远程仓库中查找(这种就和正式版本的行为一样)
一般在代码仓库的 pom.xml 文件里面没有看到 maven 配置这个信息,因为 daily 配置是默认值;
<repositories>
<repository>
<id>myRepository</id>
<url>http</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
</snapshots>
</repository>
</repositories>
在Gradle,可以设置本地缓存的更新策略。
configurations.all {
// check for updates every build
resolutionStrategy.cacheChangingModulesFor 0,'seconds'
# resolutionStrategy.cacheChangingModulesFor 10, ‘minutes'
# resolutionStrategy.cacheChangingModulesFor 4, ‘hours'
}
总结:在开发模式下,可以频繁的发布SNAPSHOT版本,以便让其它项目能实时的使用到最新的功能做联调;当版本趋于稳定时,再发布一个正式版本,供正式使用。当然在做正式发布时,也要确保当前项目的依赖项中不包含对任何SNAPSHOT版本的依赖,保证正式版本的稳定性;否则可能不能发布成功(即校验是否含有 snapshot 依赖)
maven-shade-plugin
项目根目录发现有一个只有一次提交记录的pom文件:dependency-reduced-pom.xml
,使用maven-shade-plugin插件打jar包就会生成这个问题,添加配置来避免文件的生成:
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
用maven-shade-plugin
插件来deploy或者发布到中央仓库,createDependencyReducedPom属性会缩减你的pom文件,会把你依赖的<dependency>
干掉。
存在的意义:
也就是说,假如我的一个工程A依赖了spring-boot-starter-tomcat,那么这个依赖(即spring-boot-starter-tomcat)中的.class文件会被打包进生成的A.jar包中, 而在生成的dependency-reduced-pom.xml
文件中,这个依赖将被exclusion掉。
dependency-reduced-pom.xml
有什么用呢?
如果在另一个工程B中引用了A工程对应的A.jar,而且B也依赖了spring-boot-starter-tomcat,那么我们在B工程中就不需要再依赖spring-boot-starter-tomcat了,这样可以避免重复引用。
provided和optional
optional
关于 optional,最常见的例子就是数据库驱动。例如我们想做一个数据库组件,而且这个数据库组件需要支持多个数据库的话,例如 MySQL、PostgreSQL、Oracle,那么组件端编写的时候将各个数据库的驱动全部引入:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc14</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
这样数据库组件倒是可以正常开发了,但是这样做的话,构建出的数据库组件,就同时包含了 mysql、oracle、postgresql 三种数据库的驱动包。应用服务引入了我们的数据库组件后,由于依赖传递,就也会同时引入了上面三种数据库驱动包,加大了应用服务打包后的体积,也浪费了资源,甚至可能出现依赖冲突、jar 包冲突的问题。
optional 就是为了解决上述问题。回到上面的场景,分析后发现,实际上的应用服务不太可能同时使用三种不同的数据库,它只需要自己用到的数据库的驱动包就可以了。比如一个使用了 mysql 的服务,是没有必要引入 oracle 的驱动包的。这时候 optional 就派上用处了。optional 表示该依赖是可选的,意味着构建后,标记为 optional 的依赖是不会被一起打入 jar 包的,也不会发生依赖传递。这样不仅我们自己的组件端体积变小了,应用服务也解决了引入过多无用依赖的问题。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc14</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<optional>true</optional>
</dependency>
按照上面的方式将各个依赖设置为 optional 后,打包构建的 jar 将不再包含以上三种数据库的驱动,这样其他应用服务引入了我们的组件后,就不会默认带上上面的数据库驱动包。
可能有同学会疑虑,如果依赖没有带入,那么程序运行期间,会不会发生类找不到的问题?确实是这样的,实际上 optional 表示可选,它将选择权交给了上层应用服务。假如我的服务使用了 mysql,那么我就在服务自己的 pom.xml 中引入 mysql 的驱动包;如果用的是 oracle,同理也是自己引入 oracle 的驱动包,也就是按需使用。如果服务没有引入任何数据库驱动,那么最坏的情况应该是不会使用数据库相关的功能,而不是报错。
optional 更是一种规范:
optional 通常用于组件端应用,即一个 jar 包,而不是一个应用服务;
optional 的依赖不会一起被打包,不会经过依赖传递而引入上层应用服务中;
optional 的依赖,表示可选,及时没有该依赖,也不影响程序运行,这里需要程序进行一些额外的判断逻辑;
optional 的依赖,由上层应用服务来选择是否引入。
举个大白话的例子,去面馆吃面,那么面馆肯定不会把各种调料都放满,而是将选择权交给顾客,顾客按照自己的口味来添加调味料,加不加、加什么,都是顾客自己选。
provided
标记为 provided 的依赖,和 optional 其实效果是一样的,都不会被直接的打入包中,不会通过依赖传递而传递到上层应用服务的依赖中。
这里其实,二者虽然在效果上没有直接的区别,但是二者的使用场景不一样。上面说了 optional 主要用于“可选依赖”的场景,依赖是否引入,都不会影响服务正常运行。而 provided 表示的不是依赖可选,它表示这个依赖是必须的,但是这个依赖通常是已经提供的,应用服务不需要额外引入,通常也不用关心。例如很多人使用 tomcat 作为服务运行容器,tomcat 自己会提供一些必备的依赖项,这些依赖项对于服务正常运行必须的,但是对于应用服务来说,这些依赖项是已经提供好的,不需要自己关心。
所以很多时候,会有人将 optional 与 provided 弄混,甚至一起使用,而且通常情况下是没有什么问题的。虽然二者的行为是一致的,但是对于二者规定的规范确实不同的:
optional 表示某个依赖可选,该依赖是否使用都不会影响服务运行。
provided 表示某个依赖必须,不过该依赖通常是由系统或者容器提供,不需要自己关系。
删除.lastUpdated
文件
项目使用maven管理jar包,很容易因为各种原因(网速慢、断网)导致jar包下载不下来,出现很多.lastUpdated文件。这些文件一个一个删除太麻烦。全部删除的方法,del-lastUpdated.bat:
@echo off
rem create by NettQun
rem 这里写你的仓库路径
set REPOSITORY_PATH=C:\Users\johnn\.m2\repository
rem 正在搜索...
for /f "delims=" %%i in ('dir /b /s "%REPOSITORY_PATH%\*lastUpdated*"') do (
echo %%i
del /s /q "%%i"
)
rem 搜索完毕
pause
参考
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/142415.html