Maven常见错误解决方案以及常用技巧

常用的高级玩法:
(1)使用-选项时,和后面的参数之间可以不要空格。而使用–选项时,和后面的参数之间必须有空格。

mvn help:describe -Dcmd=compiler:compile
mvn install --define maven.test.skip=true

(2)显示版本信息参数“-V”和“-v”有区别

mvn -V clean package  # --show-version 显示版本信息后继续执行Maven其他目标
mvn -v	#-version 显示版本信息。

用途:当想让Maven版本信息出现在构建输出的开始处,你应该使用-V选项。如果你正在持续构建环境里运行Maven,并且你需要知道特定构建使用了哪个Maven版本,-V选项就可以派上用场。

(3)离线模式下的运行
阻止通过网络更新插件或依赖:

-o  # --offline 离线模式工作,该参数可以阻止通过网络更新插件或依赖。

(4)加密密码
下面的命令允许你使用Maven加密密码,然后存储到Maven settings文件里:

-emp,--encrypt-master-password <password> 加密主安全密码
-ep,--encrypt-password <password>  加密服务器密码

(5)多模块执行过程中的失败处理
下面的选项控制,在多模块项目构建的中间阶段,Maven如何应对构建失败:

-fae, --fail-at-end 仅影响构建结果,允许不受影响的构建继续(跳过失败的模块,编译到最后再报错)
-ff, --fail-fast 遇到构建失败就停下来
-fn,--fail-never 无论项目结果如何,构建从不失败

解析:-fn 和 -fae选项对于使用持续集成工具(例如Hunson、Jenkins)的多模块构建非常有用。 -ff 选项对于运行交互构建的开发者非常有用,因为开发者在开发周期中想得到快速的反馈。

(6)配置Maven本身日志输出

-e, --errors 产生执行错误相关消息

-X, --debug 产生执行调试信息

-q, --quiet 仅仅显示错误

解析:只有出现错误或问题,-q 选项才打印一条消息。-X 选项会打印大量的调试日志消息,这个选项主要被Maven开发者和Maven插件开发者用来诊断在开发过程中碰到的Maven代码问题。如果你想诊断依赖或路径问题,-X 选项也非常有用。如果你是Maven开发者,或者你需要诊断Maven插件的一个错误,那么-e选项就会派上用场。如果你想报告Maven或Maven插件的一个未预料到的问题,你应该传递-X 和 -e命令行选项。

(7)用批处理方式运行Maven
要在批处理模式下运行Maven,使用下面的选项:

-B, --batch-mode 在非交互(批处理)模式下运行

如果你需要在非交互、持续集成环境下运行Maven,必须要使用批处理模式。在非交互模式下运行,当Mven需要输入时,它不会停下来接受用户的输入,而是使用合理的默认值。

(8)依赖的下载和验证
下面的命令行选项会影响Maven和远程仓库的交互以及Maven如何验证下载的构件:

-C, --strict-checksums 如果校验码不匹配的话,构建失败

-c, --lax-checksums 如果校验码不匹配的话,产生告警

-U, --update-snapshots 在远程仓管更新发布版本或快照版本时,强制更新。

如果你关注安全,你就想带 -C选项运行Maven。Maven仓库为每个存储在仓库里的构件维护一个MD5 和 SHA1 校验码。如果构件的校验码不匹配下载的构件,Maven默认被配置成告警终端用户。如果传递-C 选项,当遇到带着错误校验码的构件,会引起Maven构建失败。如果你想确保Maven检查所有快照依赖的最新版本,-U选项非常有用。

(9)控制插件更新
下面的命令行选项告诉Maven,它将如何从远程仓库更新(或不更新)Maven插件:

-npu,--no-plugin-updates 对任何相关的注册插件,不进行最新检查。使用该选项使Maven表现出稳定行为,该稳定行为基于本地仓库当前可用的所有插件版本。

-cpu, --check-plugin-updates 对任何相关的注册插件,强制进行最新检查。强制Maven检查Maven插件的最新发布版本,即使在你的项目POM里明确规定了Maven插件版本,还是会强制更新。

-up, --update-plugins cpu的同义词.

下面的命令行选项影响Maven从远处仓库下载插件的方式:

-npr, --no-plugin-registry 对插件版本不使用~/.m2/plugin-registry.xml  里的配置。

-npr 命令行选项告诉Maven不要参考插件注册表。欲了解关于插件注册表的更多信息,去这里:http://maven.apache.org/guides/introduction/introduction-to-plugin-registry.html.

(10)非递归构建(只运行当前目录下的项目)
有时,你只想运行Maven构建,而不陷入项目子模块的构建。通过使用下面的命令行选项:

-N, --non-recursive 阻止Maven构建子模块。仅仅构建当前目录包含的项目

运行该命令行选项使Maven只为当前目录下的项目执行生命周期中的目标或步骤。

(11)执行时指定特定的文件
运行时指定pom.xml文件pom-demo.xml:

-f pom-demo.xml		# --file <file> 强制使用备用的POM文件

运行时指定settings.xml文件settings-demo.xml:

-s settings-demo.xml		# --settings <arg> 用户配置文件的备用路径

运行时指定全局配置文件settings.xml文件settings-global.xml:

-gs settings-global.xml		# --global-settings <file> 全局配置文件的备用路径

(12)裁剪反应堆

-am, --also-make 同时构建所列模块的依赖模块。必须和-pl同时使用。如 mvn -pl test -am ,将同时构建test的依赖模块。

-amd, --also-make-dependents 同时构建依赖于所列模块的模块。必须和-pl同时使用。如 mvn -pl test -amd ,将同时构建所有依赖test的模块。

-pl, --projects <arg> 构建指定的模块,模块间用逗号分隔。可以用来切割大型maven项目,达到急速构建的目的。

-rf, --resume-from <arg> 让反应堆从指定的模块开始构建。通俗点说就是指定从哪个模块开始构建。编译失败后,接着编译。

详细用法请参考:http://books.sonatype.com/mvnref-book/reference/_using_advanced_reactor_options.html
https://books.sonatype.com/mvnref-book/reference/running-sect-options.html

(13)常用Maven 内置变量

${basedir} 项目根目录(即pom.xml文件所在目录)
${project.build.directory} 构建目录,缺省为target目录
${project.build.outputDirectory} 构建过程输出目录,缺省为target/classes
${project.build.finalName} 产出物名称,缺省为${project.artifactId}-${project.version}
${project.packaging} 打包类型,缺省为jar
${project.xxx} 当前pom文件的任意节点的内容
${env.xxx} 获取系统环境变量。例如,"env.PATH"指代了$path环境变量(在Windows上是%PATH%)。
${settings.xxx} 指代了settings.xml中对应元素的值。例如:<settings><offline>false</offline></settings>通过 ${settings.offline}获得offline的值。
Java System Properties: 所有可通过java.lang.System.getProperties()访问的属性都能在POM中使用,例如 ${JAVA_HOME}

(14)关于坐标
<主版本>.<次版本>.<增量版本>-<限定符>、
其中主版本主要表示大型架构变更,次版本主要表示特性的增加,增量版本主要服务于bug修复,而限定符如alpha、beta等等是用来表示里程碑。当然不是每个项目的版本都要用到这些4个部分,根据需要选择性的使用即可。

(15)帮助规划坐标:Classifier
classifier可能是最容易被忽略的Maven特性,classifier可以是指定任意字符串,用于拼接在GAV之后来确定生成的文件内容,例如:包含源代码、包含javadoc、类文件等。最常用的装配插件:maven-assembly-plugin

例如:json-lib-2.2.2-jdk15.jar

<dependency>  
    <groupId>net.sf.json-lib</groupId>   
    <artifactId>json-lib</artifactId>   
    <version>2.2.2</version>  
    <classifier>jdk15</classifier>    
</dependency>

例如:json-lib-2.2.2-jdk15-javadoc.jar

<dependency>  
    <groupId>net.sf.json-lib</groupId>   
    <artifactId>json-lib</artifactId>   
    <version>2.2.2</version>  
    <classifier>jdk15-javadoc</classifier>    
</dependency> 

但是一定要注意classifier的位置:

<dependency>  
    <groupId>net.sf.json-lib</groupId>   
    <artifactId>json-lib</artifactId>   
    <classifier>jdk15-javadoc</classifier>  
    <version>2.2.2</version>   
</dependency>

生成出来的文件名:json-lib-jdk15-javadoc-2.2.2.jar

(16)POM文件重构技巧
一般情况,随着项目越做越久,越做越大,往往依赖关系就会变的复杂,就会引入用不到的依赖,需要重构。

  1. 当前模块与父模块使用同样的groupId和version时,就可以将和元素删除
  2. 使用标签properties提取相同版本号为变量。模块越多,潜在的重复就越多,重构就越有必要。
  3. 对插件指定groupId和version。例如:缺少指定groupId和version时:Maven默认是官方插件;缺少指定version时,Maven会默认使用最新版本(Maven2会使用最新的版本,包括SNAPSHOT,而Maven 3则只使用最新的非SNAPSHOT版本)。

那么如何知道哪些依赖是用到的,哪些是用不到的呢??
Maven官方还提供了一个非常有用的Maven Dependency Plugin来帮助我们分析项目中哪些依赖配置应该删除,那些依赖配置应该增加。

mvn dependency:analyze
[INFO] --- maven-dependency-plugin:2.1:analyze (default-cli) @ sample-bar ---
[WARNING] Used undeclared dependencies found:
[WARNING]    org.springframework:spring-context:jar:2.5.6:compile
[WARNING] Unused declared dependencies found:
[WARNING]    org.springframework:spring-core:jar:2.5.6:compile
[WARNING]    org.springframework:spring-beans:jar:2.5.6:compile
[INFO] ------------------------------------------------------------------------

解析:
第一部分:Used undeclared dependencies 是指那些在项目中直接使用到的,但没有在POM中配置的依赖,所以,应该在POM中显式的声明和指定。 例如:上面输出的org.springframework:spring-context:jar:2.5.6,是已经配置的依赖引入的(也就是依赖的依赖),这就存在一定的风险,因为对于传递性依赖的变化比较模糊,当这种变化造成构建失败时,就很难找到原因了。
第二部分:Unused declared dependencies,这表示那些我们配置了,但并未直接使用的依赖。需要注意的时,对于这些依赖,我们不该直接简单地删除。由于dependency:analyze只分析编译主代码和测试代码使用的依赖,一些执行测试和运行时的依赖它发现不了,因此还需要人工分析。通常情况,Unused declared dependencies 还是能帮助我们发现一些无用的依赖配置。

  1. 消除多模块依赖配置重复。使用继承机制以及dependencyManagement元素解决多个模块使用共同依赖的问题。
    父模块中配置dependencies时,所有子模块都自动继承,虽然达到了统一依赖的问题,但是对于某些子模块用不到的依赖,也会直接继承。
    父模块中配置dependencyManagement只会影响现有依赖的配置,但不会引入依赖。例如:
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactid>junit</artifactId>
      <version>4.8.2</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactid>log4j</artifactId>
      <version>1.2.16</version>
    </dependency>
  </dependencies>
</dependencyManagement>

这段配置不会给任何子模块引入依赖,但如果某个子模块需要使用JUnit和Log4j的时候,我们就可以简化依赖配置成这样:

<dependency>
    <groupId>junit</groupId>
    <artifactid>junit</artifactId>
  </dependency>
  <dependency>
    <groupId>log4j</groupId>
    <artifactid>log4j</artifactId>
  </dependency>

现在只需要groupId和artifactId,其它元素如version和scope都能通过继承父POM的dependencyManagement得到,如果有依赖配置了exclusions,那节省的代码就更加可观。但重点不在这,重点在于现在能够保证所有模块使用的JUnit和Log4j依赖配置是一致的。而且子模块仍然可以按需引入依赖,如果我不配置dependency,父模块中dependencyManagement下的其他依赖不会对我产生任何影响。

在多模块Maven项目中,dependencyManagement几乎是必不可少的,因为只有它是才能够有效地帮我们维护依赖一致性。

分类管理时怎么办??
如果项目比较大,共同维护一个父pom中dependencyManagement下的依赖,就会比较混乱,不能分门别类的清晰管理,这时可以通过:import scope解决。
你可以把dependencyManagement放到单独的专门用来管理依赖的POM中,然后在需要使用依赖的模块中通过import scope依赖,就可以引入dependencyManagement。例如可以写这样一个用于依赖管理的POM:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.juvenxu.sample</groupId>
  <artifactId>sample-dependency-infrastructure</artifactId>
  <packaging>pom</packaging>
  <version>1.0-SNAPSHOT</version>
  <dependencyManagement>
    <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactid>junit</artifactId>
          <version>4.8.2</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>log4j</groupId>
          <artifactid>log4j</artifactId>
          <version>1.2.16</version>
        </dependency>
    </dependencies>
  </dependencyManagement>
</project>

然后我就可以通过非继承的方式来引入这段依赖管理配置:

<dependencyManagement>
    <dependencies>
        <dependency>
          <groupId>com.juvenxu.sample</groupId>
          <artifactid>sample-dependency-infrastructure</artifactId>
          <version>1.0-SNAPSHOT</version>
          <type>pom</type>
          <scope>import</scope>
        </dependency>
    </dependencies>
  </dependencyManagement>

  <dependency>
    <groupId>junit</groupId>
    <artifactid>junit</artifactId>
  </dependency>
  <dependency>
    <groupId>log4j</groupId>
    <artifactid>log4j</artifactId>
  </dependency>

这样,父模块的POM就会非常干净,由专门的packaging为pom的POM来管理依赖,也契合的面向对象设计中的单一职责原则。此外,我们还能够创建多个这样的依赖管理POM,以更细化的方式管理依赖。这种做法与面向对象设计中使用组合而非继承也有点相似的味道。

  1. 消除多模块插件配置重复。与dependencyManagement类似的,我们也可以使用pluginManagement元素管理插件。
    与依赖配置不同的是,通常所有项目对于任意一个依赖的配置都应该是统一的,但插件却不是这样,例如你可以希望模块A运行所有单元测试,模块B要跳过一些测试,这时就需要配置maven-surefire-plugin来实现,那样两个模块的插件配置就不一致了。这也就是说,简单的把插件配置提取到父POM的pluginManagement中往往不适合所有情况,那我们在使用的时候就需要注意了,只有那些普适的插件配置才应该使用pluginManagement提取到父POM中。
    关于插件pluginManagement,Maven并没有提供与import scope依赖类似的方式管理,那我们只能借助继承关系,不过好在一般来说插件配置的数量远没有依赖配置那么多,因此这也不是一个问题。

最后,重构的前提是完善的自动化测试和持续集成。

(17)项目信息说明

<project>
  <!-- 项目描述,产生文档时用 -->
  <description>...</description>
  <!-- 项目主页的URL,产生文档时用 --> 
  <url>...</url>
  <!--描述了项目的license,用于生成项目的web站点的license页面,其他一些报表和validation也会用到该元素 -->
  <licenses>...</licenses>
  <!--描述项目所属组织的各种属性,Maven产生的文档用 -->
  <organization>...</organization>
  <!-- 项目开发者列表 -->
  <developers>...</developers>
  <!--项目的问题管理系统(Bugzilla, Jira, Scarab) -->
  <issueManagement>...</issueManagement>
  <!--项目持续集成信息 -->
  <ciManagement>...</ciManagement>
  <!-- 项目相关邮件列表信息 -->
  <mailingLists>...</mailingLists>
  <!--SCM(Source Control Management)标签允许你配置你的代码库,供Maven web站点和其它插件使用 -->
  <scm>...</scm>
</project>

(18)查看当前正在使用的setting.xml文件
mvn help:effective-settings进行查看正在起作用的是那个settings.xml的内容。
关于mvn help还有许多有用的功能可以自行学习。

1、运行Maven时报错:No goals have been specified for this build

详细报错信息:

No goals have been specified for this build. 
You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. 
Available lifecycle phases are: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean, pre-site, site, post-site, site-deploy. -> [Help 1] 

解决办法
pom.xml文件标签后面加上compile即可

2、Project configuration is not up-to-date with pom.xml错误解决方法

有时候新导入项目后也会出现这个错误。

其实这个问题解决非常简单:
在项目上右键——【Maven】——【Update Project Configuration……】
这时会打开一个(Update Maven Dependencies)的对话框,然后勾选住出错的项目,点击Ok
这样就搞定了。

3、如何用maven 手动把本地jar安装到本地仓库和将本地项目打包并安装到本地资源仓库

例如:expression-analyzer-1.2.jar
在DOS窗口中,通过如下指令:

mvn install:install-file  -Dfile=C:/Users/zhangmengjiao/Desktop/expression-analyzer-1.2.jar  -DgroupId=com.delta.jar  -DartifactId=expression-analyzer -Dversion=1.2 -Dpackaging=jar

(如果在中央仓库中找不到依赖的包,则要手动添加到本地仓库中)

4、Maven打包时,过滤掉测试代码:

常用运行时执行:mvn clean install -Dmaven.test.skip=true

-DskipTests  # 不执行测试用例,但编译测试用例类生成相应的 class 文件至 target/test-classes 下
-Dmaven.test.skip=true  # 不执行测试用例,也不编译测试用例类
5、打可执行jar,并设置Class-path:

在中新增:

<plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-jar-plugin</artifactId>
          <version>2.4</version>
          <configuration>
                   <archive>
                             <manifest>
                                      <addClasspath>true</addClasspath>
                                      <classpathPrefix>lib/</classpathPrefix>
                                     <mainClass>com.delta.cornerstone.runtime.RuntimeEngine</mainClass>      // 指定主类
                             </manifest>
                             <manifestEntries>  // 添加class-path
                                   <Class-Path>config/ persistenceEntity/</Class-Path>
                          </manifestEntries>
                   </archive>
          </configuration>
 </plugin>

另外:应用maven-jar-plugin打包插件,可以修改生成的jar文件名,并且指定jar文件的输出路径以及jar文件的classpath,如下:

<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-jar-plugin</artifactId>
			<version>2.4</version>
			<configuration>
				<finalName>自定义名</finalName>
				<archive>
					<manifest>
						<addClasspath>true</addClasspath>
<!-- 增加classpath -->
						<!-- <classpathPrefix>config/ lib/</classpathPrefix> -->
					</manifest>
				</archive>
<!-- 指定jar文件的生成路径 -->
<outputDirectory>../HelloWorld/Scm-Common</outputDirectory>
			</configuration>
		</plugin>

将项目依赖的jar文件也复制(导出)到指定文件夹下:
<!-- include dependency jar -->
  		<plugin>
  			<groupId>org.apache.maven.plugins</groupId>
  			<artifactId>maven-dependency-plugin</artifactId>
  			<executions>
  				<execution>
	  				<id>copy-dependencies</id>
	  				<phase>prepare-package</phase>
	  				<goals>
	  					<goal>copy-dependencies</goal>
	  				</goals>
	  				
	  				 <configuration>
	  				 	<outputDirectory>../HelloWorld/Scm-Common/lib</outputDirectory>
	  				 	<overWriteReleases>false</overWriteReleases>
	  				 	<overWriteSnapshots>false</overWriteSnapshots>
	  				 	<overWriteIfNewer>true</overWriteIfNewer>
	  				 </configuration>
	  			</execution>
  			</executions>
  		</plugin>
6、本地项目依赖时的问题

在开发阶段,往往会存在项目之间的依赖关系,但pom中声明的依赖都是从仓库中获取的,为了本地运行,就必须要先将本地项目install到本地仓库或者远程仓库中,但是这样会给调试阶段带来一个问题——调试时看不到源码
两种情况:

  1. 在项目开发阶段时,我们想优先使用工作空间的项目代替maven库中的jar包。
  2. 项目测试时我们想优先使用maven库中的jar包代替工作空间的项目。

Maven的实现机制:maven项目在查找依赖时会首先查看工作空间是否有满足当前groupid,artifactid, version条件的项目,如果有就会将其引入进来,此时你在maven的依赖里就会看到文件夹形式的依赖,这就是项目依赖。否则你就会看到一个jar包被引入进来。如下图:
在这里插入图片描述
解决方案

  1. 在项目开发阶段时,我们想优先使用工作空间的项目代替maven库中的jar包;
    在同一个工作空间中,保证项目引用的GAV是另外的Maven项目即可,如果不是文件夹显示,则手动更新一下引用项目,被引用的项目不变。
  2. 项目测试时我们想优先使用maven库中的jar包代替工作空间的项目
    a.关闭工作空间中打开的被引用的项目。此时maven会自动使用maven库中的jar包进行编译。
    b. 或者修改被引用项目的groupid,artifactid,version中的一个参数,此时maven由于在工作空间中找不到相对应的项目也会自动使用maven库中的jar包进行编译(建议修改version参数),但并不建议使用这个方法。
7、maven-assembly-plugin的使用

maven-assembly-plugin 就是用来帮助打包用的,比如说打出一个什么类型的包,包里包括哪些内容等等。
目前至少支持以下打包类型:
● zip
● tar
● tar.gz
● tar.bz2
● jar
● dir
● war
默认情况下,打jar包时,只有在类路径上的文件资源会被打包到jar中,并且文件名是 a r t i f a c t I d − {artifactId}- artifactId{version}.jar,下面看看怎么用maven-assembly-plugin插件来定制化打包。
首先需要添加插件声明:

<plugin>  
    <groupId>org.apache.maven.plugins</groupId>  
    <artifactId>maven-assembly-plugin</artifactId>  
    <version>2.4</version>  
    <executions>  
        <execution>  
            <phase>package</phase>  
            <goals>  
                <goal>single</goal>  
            </goals>  
        </execution>  
    </executions>  
</plugin>  

使用内置的Assembly Descriptor,要使用maven-assembly-plugin,需要指定至少一个要使用的assembly descriptor 文件,对于当前使用的版本(2.4)对应的assembly descriptor的schema定义为:Assembly Schema ,其中assembly descriptor中又可以包括 component 的定义 (component 可以很方便的用于多个assembly descriptor之间共享),component 的schema 定义在:Component Schema。 关于assembly descriptor的component descriptor的更详细的说明,请见:Component Descriptor 和 Assembly Descriptor 。默认情况下,maven-assembly-plugin内置了几个可以用的assembly descriptor:
● bin : 类似于默认打包,会将bin目录下的文件打到包中
● jar-with-dependencies : 会将所有依赖都解压打包到生成物中
● src :只将源码目录下的文件打包
● project : 将整个project资源打包
要查看它们的详细定义,可以到maven-assembly-plugin-2.4.jar里去看,例如对应 bin 的assembly descriptor 如下:

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"   
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">  
  <id>bin</id>  
  <formats>  
    <format>tar.gz</format>  
    <format>tar.bz2</format>  
    <format>zip</format>  
  </formats>  
  <fileSets>  
    <fileSet>  
      <directory>${project.basedir}</directory>  
      <outputDirectory>/</outputDirectory>  
      <includes>  
        <include>README*</include>  
        <include>LICENSE*</include>  
        <include>NOTICE*</include>  
      </includes>  
    </fileSet>  
    <fileSet>  
      <directory>${project.build.directory}</directory>  
      <outputDirectory>/</outputDirectory>  
      <includes>  
        <include>*.jar</include>  
      </includes>  
    </fileSet>  
    <fileSet>  
      <directory>${project.build.directory}/site</directory>  
      <outputDirectory>docs</outputDirectory>  
    </fileSet>  
  </fileSets>  
</assembly>

自定义Assembly Descriptor
一般来说,内置的assembly descriptor都不满足需求,这个时候就需要写自己的assembly descriptor的实现了。先从一个最简单的定义开始:

<?xml version='1.0' encoding='UTF-8'?>  
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"  
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0  
                    http://maven.apache.org/xsd/assembly-1.1.0.xsd">  
    <id>demo</id>  
    <formats>  
        <format>jar</format>  
    </formats>  
    <includeBaseDirectory>false</includeBaseDirectory>  
    <fileSets>  
        <fileSet>  
            <directory>${project.build.directory}/classes</directory>  
            <outputDirectory>/</outputDirectory>  
        </fileSet>  
    </fileSets>  
</assembly>

这个定义很简单:
● format:指定打包类型
● includeBaseDirectory:指定是否包含打包层目录(比如finalName是output,当值为true,所有文件被放在output目录下,否则直接放在包的根目录下)
● fileSets:指定要包含的文件集,可以定义多个fileSet
● directory:指定要包含的目录
● outputDirectory:指定当前要包含的目录的目的地

重要的几点:
Cornerstone会决定生成zip文件名的前半部分。
0.1会决定生成zip文件名的中间部分。
Assembly中的release会决定生成zip文件名的后半部分。
在configuration中可以配置zip文件的名字:Zip Name
注意:如果只想有finalName的名字,则在configuration中增加配置:
false,就可以将assembly中的id名字去掉。
注意:设置起始目录——如果打出来的zip包想去掉一层目录(例如A.zip,解压出来后是A文件夹,里面才是真正的东西),则需要在Assembly定义文件中设置:false

8、maven内置属性

大体上可以将内置属性分为六大类:

  1. Maven预定义的内置属性
${basedir}表示项目根目录,即包含pom.xml文件的目录;
${version}表示项目版本;
${project.basedir}同${basedir};
${project.baseUri}表示项目文件地址;
${maven.build.timestamp}表示项目构件开始时间;
${maven.build.timestamp.format}表示属性${maven.build.timestamp}的展示格式,默认值为yyyyMMdd-HHmm,可自定义其格式,其类型可参考java.text.SimpleDateFormat。
  1. Pom属性
使用此类属性可以直接引用pom.xml文件中对应元素的值
${project.build.directory}表示主源码路径;
${project.build.sourceEncoding}表示主源码的编码格式;
${project.build.sourceDirectory}表示主源码路径;
${project.build.finalName}表示输出文件名称;
${project.version}表示项目版本,与${version}相同;
  1. setting.xml文件中的属性
以settings.开头的属性引用settings.xml文件中的XML元素值
${settings.localRepository}表示本地仓库的地址;
  1. Java系统属性
使用mvn help:system命令可查看所有的Java系统属性;
System.getProperties()可得到所有的Java属性;
${user.home}表示用户目录;
  1. 系统环境变量属性
所有的环境变量都可以用以env.开头的Maven属性引用
Dos中mvn help:system命令可查看所有环境变量;
${env.JAVA_HOME}表示JAVA_HOME环境变量的值;
  1. 自定义属性
在pom.xml文件的<properties>标签下定义的Maven属性
特别要注意的一点是,可以以参数的形式传入到项目中(pom),且用<properties>接收参数。
例如:
<project>
  <properties>
    <my.file.path>filePath</my.file.path>
  </properties>
</project>
在其他地方使用${my.file.path}使用该属性值.
9、maven中的时间戳问题:

利用上面提到的内置属性 m a v e n . b u i l d . t i m e s t a m p 和 {maven.build.timestamp}和 maven.build.timestamp{maven.build.timestamp.format},具体用法如下:

<project……>
      
<!-- 定义时间戳的格式,默认格式是:yyyyMMdd-HHmm(20160908-1304) -->
<properties>
       <maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
</properties>
      
       <!--  在artifactId中使用时间戳  -->
       <artifactId>${maven.build.timestamp}</artifactId>
      
</project>

特别要注意的是:在同一个pom文件中,可以直接这样使用,但是如果想在另外的文件(例如assembly.xml)中使用,则需要使用自定义标签。使用方式如下:

(1)在相关的pom.xml文件中
<project……>
      
<properties>
<!-- 定义时间戳的格式,默认格式是:yyyyMMdd-HHmm(20160908-1304)-->
       <maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
       <!-- 在pom.xml中自定义时间戳标签 -->
       <time.string>
              ${maven.build.timestamp}
       </time.string>
</properties>
      
       <!--  在artifactId中使用时间戳  -->
       <artifactId>${time.string }</artifactId>
      
</project>
 
(2)在相应的assembly.xml文件中,引用时间戳:
<assembly>
       ……
       <id>release-${time.string }</id>
       …….
</assembly>
10、如何在非maven项目中,建立父子关系,并对子项目进行管理。

如果是标准的maven项目,可以直接在父maven项目上建立子module,虽然表面看上去父子项目如同两个独立的项目,但其实相关的IDE会自动将子项目同步到父项目中,并且父项目会自动添加子项目的相关信息。对于非maven项目,要进行一定的步骤才可以生效。具体步骤如下:
(1)建立父项目,并生成pom文件。
(2)在子项目中,声明父项目:

<parent>
		<groupId>MavenProject.build</groupId>
		<artifactId>MavenProject-parent</artifactId>
		<version>1.5</version>
	</parent>

如果如上面这样声明的话,需要屏蔽掉父pom中module中的内容,首先运行install,然后再在父pom中增加module,即可。

<!-- 父项目的pom.xml文件的相对路径。相对路径允许你选择一个不同的路径。默认值是…/pom.xml。Maven首先在构建当前项目的地方寻找父项目的pom,其次在文件系统的这个位置(relativePath位置),然后在本地仓库,最后在远程仓库寻找父项目的pom。(如果不声明relativePath则自动从本地仓库或者中央仓库中寻找) -->

<relativePath />

所以,建议在子项目中如下声明父项目:

<parent>
		<groupId>MavenProject.build</groupId>
		<artifactId>MavenProject-parent</artifactId>
		<version>1.5</version>
<relativePath>../MavenProject-Build</relativePath>
	</parent>

(3)运行父项目中的POM文件即可。

11、常用插件
<build>
  	<plugins>
  		<plugin>
  			<!-- 编译插件 -->
  			<groupId>org.apache.maven.plugins</groupId>
  			<artifactId>maven-compiler-plugin</artifactId>
  			<version>2.3.2</version>
  			<configuration>
  				<source>1.6</source>
  				<target>1.6</target>
  				<encoding>UTF-8</encoding>
		
				<!-- 比较重要的配置,将依赖生成到某个目录下 -->
				<compilerArguments>
					<extdirs>${project.basedir}/src/main/webapp/WEB-INF/lib</extdirs>
				</compilerArguments>
				
  			</configuration>
  		</plugin>


  		<plugin>
  			<!-- 发布插件 -->
  			<groupId>org.apache.maven.plugins</groupId>
  			<artifactId>maven-deploy-plugin</artifactId>
  			<version>2.5</version>
  		</plugin>
  		<plugin>
  			<!-- 打包插件 -->
  			<groupId>org.apache.maven.plugins</groupId>
  			<artifactId>maven-jar-plugin</artifactId>
  			<version>2.3.1</version>
  		</plugin>
  		<plugin>
  			<!-- 安装插件 -->
  			<groupId>org.apache.maven.plugins</groupId>
  			<artifactId>maven-install-plugin</artifactId>
  			<version>2.3.1</version>
  		</plugin>
  		<plugin>
  			<!-- 单元测试插件 -->
  			<groupId>org.apache.maven.plugins</groupId>
  			<artifactId>maven-surefire-plugin</artifactId>
  			<version>2.7.2</version>
  			<configuration>
  				<skip>true</skip>
  			</configuration>
  		</plugin>
  		<plugin>
  			<!-- 源码插件 -->
  			<groupId>org.apache.maven.plugins</groupId>
  			<artifactId>maven-source-plugin</artifactId>
  			<version>2.1</version>
  			<!-- 发布时自动将源码同时发布的配置 -->
  			<executions>
		    	<execution>
		    		<id>attach-sources</id>
		     		<goals>
		       			<goal>jar</goal>
		      		</goals>
		     	</execution>
		    </executions>
  		</plugin>
  	</plugins>
  </build> 
12、利用Maven复制文件

首先最好定义好复制文件的路径以及目标路径,如下:

 <properties>
              <!-- 要复制文件路径 -->
                     <Hibernate.Cofigure.Path>
                            ../Cornerstone-Persistence
                     </Hibernate.Cofigure.Path>
                    
<!-- 要复制文件到目标路径 -->
                     <To.Hibernate.Path>
                            ../Cornerstone-Runtime/hibernate
                     </To.Hibernate.Path>
       </properties>

利用插件实现复制文件功能:

<build>
       <plugins>
              <plugin>
                     <artifactId>maven-antrun-plugin</artifactId>
                     <executions>
                            <execution>
                                   <id>first</id>
                                   <phase>compile</phase>
                                   <goals>
                                          <goal>run</goal>
                                   </goals>
                                   <configuration>
                                          <tasks>
                                                 <!-- overwrite=true,即直接覆盖复制 -->
                                                 <copy file="${Hibernate.Cofigure.Path}/hibernate/hibernate.cfg.xml" tofile="${To.Hibernate.Path}/hibernate.cfg.xml" overwrite="true"/>
                                          </tasks>
                                   </configuration>
                            </execution>

                      <!—复制多个文件时,需要重新添加一个execution -->
                            <execution>
                                   <id>second</id>
                                   <phase>compile</phase>
                                   <goals>
                                          <goal>run</goal>
                                   </goals>
                                   <configuration>
                                          <tasks>
                                                 <copy file="${Hibernate.Cofigure.Path}/hibernate/config.xml" tofile="${To.Hibernate.Path}/config.xml" overwrite="true"/>
                                          </tasks>
                                   </configuration>
                            </execution>
                     </executions>
              </plugin>
</build>

注意:在运行复制后,目标文件夹下可能并没有出现要复制的文件,这时需要自己手动创建文件夹。再不行就要自己创建一个与要复制的文件名相同文件名的文件。
其中,tasks中也可以定义delete操作:

<delete file="${projectg.build.directory}/classes/jdbc.properties">
13、复制依赖Jar到固定目录
<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
14、将项目打成zip包,利用插件:maven-assembly-plugin
<plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-assembly-plugin</artifactId>
                     <version>2.4</version>
                     <configuration>
                            <!—打成zip后的文件名Huxuekao-release(见12) -->
                            <finalName>MyFileName</finalName>
                            <!—指定assembly描述文件的位置/路径— --> 
   <descriptors>
                                   <descriptor>Meu-Security-assembly.xml</descriptor>
                            </descriptors>
                 <!-- <descriptorRefs> 
                      <descriptorRef>jar-with-dependencies</descriptorRef> 
                 </descriptorRefs> -->
                <!—指定打包文件生成的位置/路径— --> 
                 <outputDirectory>
                          ../Cornerstone-Test/Cornerstone-Test
                   </outputDirectory>
                
                     </configuration>
                     <executions>
                            <!-- 当执行mvn package时才会打包 -->
                            <execution>
  <!-- id是任意的,当有多个时,id要唯一 -->
                                   <id>make-assembly</id>
  				  <!-- 将该插件绑定到phase所设置的生命周期上 -->
                                   <phase>package</phase>
                                   <goals>
                                          <!-- 只打包一次 -->
                                          <goal>single</goal>
                                   </goals>
                            </execution>
                     </executions>
              </plugin>

Assembly.xml文件示例:

<assembly  
    xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">  
	<id>release</id>
	<formats>
		<!-- zip,tar,tar.gz,tar.bz2,jar,dir,war -->
		<format>zip</format>
	</formats>
	
	<dependencySets>
		<dependencySet>
			<!-- 依赖包的输出路径 -->
			<outputDirectory>/lib</outputDirectory>
			
			<!-- 当前项目构件是否包含在这个依赖集合里 -->
			<useProjectArtifact>false</useProjectArtifact>
			
			<scope>runtime</scope>
			
			<!-- 不需要打包的文件或者jar(如果是jar,声明方式:groupId:artifactId;如果是其他文件则直接写文件名即可),主要排除不需要依赖的jar -->
			<excludes>
        		<exclude>mavenProject.build:Common</exclude>
        		<exclude>mavenProject.build:Core</exclude>
				<exclude>*.xml</exclude>
      		</excludes>
		</dependencySet>
	</dependencySets>
	
	<!-- 需要打包的文件集 -->
	<fileSets>
		
		<fileSet>
			<includes>
				<include>meu_bpmn.xml</include>
				<include>Bpmn_Meu_startup_script.bat</include>
				<include>Bpmn_Meu_startup-script.sh</include>
			</includes>

            <!-- 需要打包文件的输出路径 -->
            <outputDirectory>/</outputDirectory>
		</fileSet>
	     <fileSet>
			<!-- 指定要打包文件的路径,可以使用变量形式、正则等 -->
	    	<directory>${meu.bpmnjar.okjar}/</directory>
		      <includes>  
		        <include>*.jar</include> 
		        <include>Test-1.2.jar</include>
		      </includes>
	        
			 <!-- 指定要排除的文件 -->
			  <excludes>
				<exclude>*.xml</exclude>
			  </excludes>
			
			<!-- 需要打包文件的输出路径 -->
	        <outputDirectory>/lib</outputDirectory>  
	    </fileSet>
		<fileSet>
			<!-- 可以直接生成文件夹config -->
            <outputDirectory>/config</outputDirectory>
		</fileSet>
	</fileSets>
</assembly>

注意:有时候会发现在生成的zip中的lib下面多出项目并未指定的jar文件,这是因为项目所依赖的jar本身有maven依赖造成的,也就是说,assembly会把项目中依赖的jar文件本身所依赖的其他jar也包含在内。

15、Maven中如何禁止插件(plugin)在子模块(module)上执行

在多模块工程下,在父工程下执行的插件默认会在其所有的子模块上也执行一遍,大多数情况下这是合理的,比如像compiler这样的插件,但是有时候也种行为可能并不是开发人员所期望的,比如使用exec插件调用一个外部脚本或命令,一般来说开发人员只希望在父工程下maven exec:exec来执行一次该命令即可,但在多模块下,你会发现这个同样的命令被执行了多次,多出来的执行是在每个子模块上执行的,于是我们需要一种方法来禁用插件在子模块上的执行,一般来说两个方法:
第一种方法:以exec插件为例,如果子模块想禁用插件可以这样配置

<!-- Disable plugin exec running on sub-modules -->  
<plugin>  
<groupId>org.codehaus.mojo</groupId>  
<artifactId>exec-maven-plugin</artifactId>  
<version>${exec.version}</version>  
<configuration>  
 	<skip>true</skip>  
</configuration>  
</plugin>  

第二种方法:将指定的execution(注意命令行执行的exectuion是default-cli)的phase设置为none,其实这是有点hack的做法,目地是将这个exection绑定到一个不存在的phase上,这样它就永远不会被触发执行了。以jar插件为例:

<plugin>  
	<groupId>org.apache.maven.plugins</groupId>  
	<artifactId>maven-jar-plugin</artifactId>  
	<version>${jar.version}</version>  
	<executions>  
		<execution>  
		<id>default-jar</id>  
		<phase>none</phase>  
	</execution>  
</executions>  
</plugin>

另外,补充一点:对于你exec这样的插件,虽然插件被禁用了,但是maven的命令行还会输出INFO信息告知某某模块的exec被skip了,这些信息会干扰一个外部脚本或命令执行的输出,所以你可以在maven exec:exec的后面加上-q参数来disable maven的日志信息。

16、一个项目如何打出不同的jar文件
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<executions>	<!-- 只要是带s的就说明里面可以有多个 -->
<execution>
	<id>unique id</id>		<!-- id必须是唯一的 -->
	<!-- <phase>package</phase> -->		<!-- phase用来指定该executio是什么阶段起作用 -->
	<goals>
<goal>jar</goal>	<!-- 必须要指定打包的目标后缀jar -->
</goals>
	<configuration>
	<finalName>jar file name</finalName>	<!-- 打包后的文件名 -->
<!-- 需要打包的文件,默认全部,可指定部分代码 -->
	<!-- <includes>
			<include>**/packagepath/**</include>
		</includes> -->
		<archive>
		<manifest>
		<addClasspath>true</addClasspath>	<!-- 增加classpath -->
		<classpathPrefix>lib/</classpathPrefix>	<!-- 在classpath中增加所用jar的路径 -->
		</manifest>
		<manifestEntries>  
	   		<Class-Path>config/</Class-Path>	 <!-- 在classpath中增加config/ -->
	   	</manifestEntries>
		</archive>
		<outputDirectory>${jig.alarm.online.meu.path}</outputDirectory>	<!-- 指定输出路径 -->
		</configuration>
		</execution>

<execution>
……
</execution>
</executions>
</plugin>
17、项目的结构不是标准

如果出现这种情况,则有可能运行pom.xml文件后,生成的jar中没有java程序编译后的class文件。尤其要注意:src/main/java源文件夹一定要存在。如果项目中只存在源文件夹src,则要修改为src/main/java。方法如下:
在这里插入图片描述
如上图,在某些情况下需要将src源文件夹修改成src/main/java(例如:Maven就要求标准的目录结构),修改方法如下:
首先,进入到该目录文件夹下,如下图:
在这里插入图片描述
在src文件夹下新建文件夹“main”,再在刚刚新建的main文件夹下新建“java”文件夹,如下图:(注意如果改项目中已经存在包和java文件,请一定要将这些文件移动到刚刚建立的“java”文件夹下)
在这里插入图片描述
然后,修改“.classpath”文件如下:
在这里插入图片描述
最后,保存修改后的文件,并在eclipse(RTC)中刷新该项目,如下:
在这里插入图片描述

18、Maven dependency中外部jar依赖

如果在项目中依赖的jar在本地和远程仓库中都没有,则至少有两种方法处理:1.首先将依赖的jar上传至本地仓库中(mvn install:install-file -Dfile=** -DgroupId=** -DartifactId=** -Dversion=** -Dpackaging=jar);2.在POM文件中systemscope的定义方式,加载本地任意路径下的jar包。对于第二种情况,例如:

<dependency>
	<groupId> commons-cli </groupId>
	<artifactId> commons-cli </artifactId>
	<version>1.0.0</version> 
	<scope>system</scope>
	<systemPath>${basedir}/libs/commons-cli.jar</systemPath>		// jar的路径
</dependency>

但是这种方法有个缺点:对于system,Maven不会把这个jar包的内容打包到最后的jar-with-dependencies.jar中。
为了解决这个问题,就要首先将该jar文件上传至repository中,在POM中MAVEN支持安装jar到本地的repository,具体POM配置如下:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-install-plugin</artifactId>
    <executions>
        <execution>
            <id>install-external</id>
            <phase>clean</phase>
            <configuration>
                <file>${basedir}/libs/commons-cli.jar</file>
                <repositoryLayout>default</repositoryLayout>
                <groupId>commons-cli</groupId>
                <artifactId>commons-cli</artifactId>
                <version>1.0.0</version>
                <packaging>jar</packaging>
                <generatePom>true</generatePom>
            </configuration>
            <goals>
                <goal>install-file</goal>
            </goals>
        </execution>
    </executions>
</plugin>

要注意的是clean,之所以要在这个阶段,是因为maven需要项目的所有依赖都得到解决之后才开始执行。

19、利用maven工具解决jar包冲突问题或重复加载问题

在使用maven开发项目的过程中,经常会遇到jar包重复加载或者jar包冲突的问题的,但是由于有些jar是由于maven的依赖加载自动加载进来的,而不是开发者自己配置的,特别是当项目中pom中配置的jar包依赖本身很多时,开发者靠自己的经验,有时很难找出是哪个jar的加载导致加载了多余的依赖jar,从而产生冲突。项目中出现的问题如下:

Caused by: Java.lang.NoClassDefFoundError: Could not initialize class org.apache.log4j.Log4jLoggerFactory

log4j-over-slf4j.jar 和 slf4j-log4j12.jar 在同一个classpath下就会出现这个错误。

解决方法:
将slf4j-log4j12.jar从相关的jar中排除,但是查看maven项目中的pom文件,自己并没有配置这个jar的依赖,猜测是maven加载其他jar引入的依赖包。
打开pom.xml文件,在Dependency Hierarchy(依赖列表)中查看jar包的依赖层次关系。
在这里插入图片描述
在过滤栏中输入log4j,右侧出现了log4j相关包的依赖结构,左侧则是pom.xml全部依赖包的列表展示。
直接在右侧选中zookeeper底下的slf4j的jar包,右键选择Exclude,然后保存pom.xml。这样在加载zookeeper的jar包时就不会再加载slf4j的jar包。
在这里插入图片描述
修改后对应的dependency文件如下:

          <dependency>
			<groupId>org.apache.zookeeper</groupId>
			<artifactId>zookeeper</artifactId>
			<version>3.4.6</version>
			<exclusions>
				<exclusion>
					<artifactId>slf4j-log4j12</artifactId>
					<groupId>org.slf4j</groupId>
				</exclusion>
			</exclusions>
		</dependency>

这样就能通过filter过滤快速找到对应jar,并知道他的依赖关系,快速解决项目中的jar包冲突问题。

20、生命周期

三套生命周期:clean(清理项目)、default(构建项目)、site(建立项目站点)。
这三套生命周期是相互独立的,总的来说:
Clean Lifecycle 在进行真正的构建之前进行一些清理工作。
Default Lifecycle 构建的核心部分,编译,测试,打包,部署等等。
Site Lifecycle 生成项目报告,站点,发布站点。

第一个生命周期:clean,包含有三个阶段步骤(按照执行顺序排序)
pre-clean 执行一些需要在clean之前完成的工作
clean 移除所有上一次构建生成的文件
post-clean 执行一些需要在clean之后立刻完成的工作
第二个生命周期:default,包含以下阶段(按照执行顺序排序)
validate 验证
generate-sources 源文件生成
process-sources 源文件处理
generate-resources 生成资源文件
process-resources 复制并处理资源文件,至目标目录,准备打包。
compile 编译项目的源代码。
process-classes
generate-test-sources
process-test-sources
generate-test-resources
process-test-resources 复制并处理资源文件,至目标测试目录。
test-compile 编译测试源代码。
process-test-classes
test 使用合适的单元测试框架运行测试。这些测试代码不会被打包或部署。
prepare-package
package 接受编译好的代码,打包成可发布的格式,如 JAR 。
pre-integration-test
integration-test
post-integration-test
verify
install 将包安装至本地仓库,以让其它项目依赖。
deploy 将最终的包复制到远程的仓库,以让其它开发人员与项目共享。
第三个生命周期:site,包含以下阶段(按照执行顺序排序)
目的:建立和发布站点信息,Maven能够基于POM所包含的信息,自动生成一个友好的站点,方便团队交流和发布项目信息。
pre-site 执行一些需要在生成站点文档之前完成的工作
site 生成项目的站点文档
post-site 执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
site-deploy 将生成的站点文档部署到特定的服务器上
命令行与生命周期:
1)mvn clean : 该命令调用clean生命周期的clean阶段。
2)mvn test : 该命令调用default生命周期到test节点。
3)mvn clean install : 该命令调用clean生命周期的clean阶段和default生命周期的install阶段。
4)mvn clean deploy site-deploy : 执行三个生命周期的三个阶段。

21、Settings文件——mirrorOf和repository加载顺序

为什么有mirror?对于以下情况就需要配置mirror即镜像:
我现在要求开发者,如果在内部工厂(私服/本地)找不到某些依赖,就不找了,归根结底就是不能去中央工厂去找(强制只能有私服才能访问中央工厂)。这时就需要配置镜像。

<!-- 只要访问mirrorOf中设置的工厂,都会自动找镜像中配置的url,不会去其他地方再找 -->
<!-- 一般情况下,mirrorOf中设置为星号*,代表所有 -->
<mirrorOf>nexus,central</mirrorOf>

settings文件中mirrors中允许配置多个镜像(也可以多个仓库地址镜像到一个url中),mirror的作用一般是为了使用一个更快速的地址。
在maven中,不配置mirror的情况下,默认使用的是Maven的中央仓库。在配置mirror时,mirrorOf通常会设置成“*”星号,还有可能是一个具体的值,还有可能用逗号隔开的几个值例如:

  1. repo1
  2. repo1,repo2,*,!repo3
  3. externa:*
    mirror是配置镜像的远程库地址的,对于mirrorOf参数,如果该镜像库的目标远程库不止一个,则可以使用*表示任意远程库;external:表示任何不在localhost和文件系统中的远程库;repo1,repo2表示repo1库或者repo2库;,!repo1表示除了repo1库之外的任何远程库。
    实现:在maven中配置一主一副两个镜像,大部分jar直接通过主镜像可以找到,部分特殊jar在主镜像中找不到时,自动去副镜像中寻找。
  1.  <mirror>    
  2.       <id>稀有-mirror</id>  
  3.       <name>稀有-mirror</name>
  4.       <url>https://稀有/repo/</url>  
  5.       <mirrorOf>central</mirrorOf>    
  6.     </mirror> 
  7.  
  8.     <mirror>    
  9.       <id>nexus-aliyun</id>  
  10.       <name>nexus-aliyun</name>
  11.       <url>http://maven.aliyun.com/nexus/content/groups/public</url>  
  12.       <mirrorOf>*</mirrorOf>  
  13.   1.  <mirror>    
  2.       <id>稀有-mirror</id>  
  3.       <name>稀有-mirror</name>
  4.       <url>https://稀有/repo/</url>  
  5.       <mirrorOf>central</mirrorOf>    
  6.     </mirror> 
  7.  
  8.     <mirror>    
  9.       <id>nexus-aliyun</id>  
  10.       <name>nexus-aliyun</name>
  11.       <url>http://maven.aliyun.com/nexus/content/groups/public</url>  
  12.       <mirrorOf>*</mirrorOf>    
  13.     </mirror>

以上配置后,当maven发现所需的稀有jar在阿里镜像中没有时,会自动去稀有镜像中寻找。稀有jar的确下载下来了。
或者在全局的settings.xml文件中配置好了central镜像后,在项目中单独配置稀有jar文件的镜像。在pom.xml中设置:

  1. <repositories>
  2.     <repository>
  3.       <id>稀有仓库</id>
  4.       <url>https://稀有仓库/public/</url>
  5.     </repository>
  6.  </repositories>
22、下载依赖的源码

1.Maven命令下载源码和javadocs
当在IDE中使用Maven时如果想要看引用的jar包中类的源码和javadoc需要通过maven命令下载这些源码,然后再进行引入,通过mvn命令能够容易的达到这个目的:

mvn dependency:sources
mvn dependency:resolve -Dclassifier=javadoc

命令使用方法:首先进入到相应的pom.xml目录中,然后执行以上命令:
第一个命令是尝试下载在pom.xml中依赖的文件的源代码。
第二个命令:是尝试下载对应的javadocs
但是有可能一些文件没有源代码或者javadocs
2.通过配置文件添加
打开maven配置文件 setting.xml文件(…/.m2/settings.xml) 增加如下配置:

<profiles>
	<profile>
	<id>downloadSources</id>
	<properties>
 			<downloadSources>true</downloadSources>
		<downloadJavadocs>true</downloadJavadocs>           
	</properties>
	</profile>
</profiles>
 
<activeProfiles>
	<activeProfile>downloadSources</activeProfile>
</activeProfiles>

3.配置eclipse
Window > Preferences > Maven and checking the “Download Artifact Sources” and “Download Artifact JavaDoc” options
在这里插入图片描述
4.直接操作eclipse中的项目
右键项目——Maven——Download Source and doc…

23、在Eclipse/RTC中运行maven时,出现-Dmaven.multiModuleProjectDirectory system property is not set. Check $M2_HOME environment variable and mvn script match.

则说明没有在IDE的JRE环境中配置参数“-Dmaven.multiModuleProjectDirectory=$M2_HOME”
在这里插入图片描述
在这里插入图片描述

24、使用maven profile指定配置文件打包适用多环境(eclipse使用profile完成不同环境的maven打包功能)

首先说明一下,如果pom.xml中有定义的<profile>标签,那么,IDEA会自动识别到,所以在使用IDEA时可以直接点击定义的<id>环境直接运行。但是,Eclipse中是不会有直接选择的地方,需要在运行时手动指定。

我们在日常开发工作中,通常会根据不同开发阶段将项目运行在开发、测试、生产等环境下,添加不同的配置文件,例如 开发环境,测试环境,生产环境等,每次手工的修改配置文件太过于繁琐。通过maven打包时确定需要使用的配置文件可以很好的解决这个问题。例如,在pom.xml中添加 profile节点信息如下:
(引用https://blog.csdn.net/hjiacheng/article/details/57413933)

<profiles>
		<profile>
			<!-- 开发环境 -->
			<id>dev</id>
			<properties>
				<environment>development</environment><!-- 节点名字environment是自己随意取的 -->
			</properties>
			<activation>
				<activeByDefault>true</activeByDefault><!-- 默认激活该profile节点-->
			</activation>
		</profile>
		<profile>
			<!-- 测试环境 -->
			<id>test</id>
			<properties>
				<environment>test</environment>
			</properties>
		</profile>
		<profile>
			<!-- 预演环境 -->
			<id>prev</id>
			<properties>
				<environment>preview</environment>
			</properties>
		</profile>
		<profile>
			<!-- 生产环境 -->
			<id>prod</id>
			<properties>
				<environment>production</environment>
			</properties>
		</profile>
</profiles>

在项目中添加各环境需要的数据源配置文件,分不同目录存放, 分别是开发,测试, 预演,生产 环境. 如下图左边部分所示.
在这里插入图片描述
pom.xml中配置resource节点信息:

	<build>			
		<resources>
			<resource>
				<directory>src/main/resources</directory>
				<excludes>
					<exclude>environment/development/*</exclude>  
					<exclude>environment/test/*</exclude>  
					<exclude>environment/preview/*</exclude>  
                	                <exclude>environment/production/**</exclude>
				</excludes>
			</resource>
			<resource>
				<directory>src/main/resources/environment/${environment}</directory>
				<targetPath>environment/${environment}</targetPath>
			</resource>
		</resources>
	</build>

resource节点信息解释:

<directory>src/main/resources</directory> <!--打包时包含src/main/resources目录下所有"子"文件 和 "孙"文件.如config 和environment -->
<exclude>environment/development/**</exclude> <!--打包时排除src/main/resources/environment/development下所有"子"文件 和 "孙"文件.-->
<exclude>environment/test/**</exclude> <!--打包时排除src/main/resources/environment/test下所有"子"文件 和 "孙"文件.-->
<exclude>environment/preview/**</exclude> <!--打包时排除src/main/resources/environment/preview下所有"子"文件 和 "孙"文件.-->
<exclude>environment/production/**</exclude><!--打包时排除src/main/resources/environment/production下所有"子"文件 和 "孙"文件.-->
<!-- 注意点: 如果写一个心号*, 如<exclude>environment/development/*</exclude> 则表示:打包时排除src/main/resources/environment/development下所有"子"文件, 不排除"孙"文件, 如上一个截图所示.-->
<!-- 以上配置优先度从上到下 递增, 这就达到目的: config目录下的配置各环境都需要, 而其它环境相关的配置只会有一个目录被打包--->
<directory>src/main/resources/environment/${environment}</directory> <!-- 打包时包含src/main/resources/environment/${environment}下所有"子"文件,environment变量值来自profile中赋值 -->
<targetPath>environment/${environment}</targetPath><!--指定src/main/resources/environment/${environment}所有"子文件" 打包 到包的哪个目录 -->

项目打包. 打包命令mvn package -Pdev来指定激活id为 dev 的profile节点, 这样, 开发环境配置文件就会被打包.
开发: mvn package -Pdev (因为配置了默认激活dev部分, 所以也可以使用mvn package, 这与 mvn package -Pdev 效果相同)
测试: mvn package -Ptest
预演:mvn package -Pprev
生产:mvn package -Pprod

多说一下
-P:是Profiles的首字母,代表指定哪个id的Profiles配置文件。通过-P进行传递或者赋值
-D:在maven中还有一个以P开头的标签——Properties属性。用D传参。
例如pom中:

<properties>
    <propertyName>defaultattr</propertyName>
</properties>

执行mvn -DpropertyName=newattr clean package,则pom.xml内propertyName的实际值将被替换成newattr
在使用-D时需要注意:

  • 如果propertyName不存在pom.xml,它将被设置。
  • 如果propertyName已经存在pom.xml,其值将被作为参数传递的值覆盖-D。
  • 如果要发送多个变量,请使用多个空格分隔符加-D:mvn -DpropA=valueA -DpropB=valueB -DpropC=valueC clean package

另外:Maven在设置时考虑到了不同运行环境的问题,所以设置了profile。当然profile可以在pom.xml中设置,也可以在setting.xml中设置。

  <profiles>
	<profile>
      <id>nexusProfile</id>
      <repositories>
        <repository>
          <id>nexus</id>
          <name>Nexus Repository</name>
          <url>http://www.myhost.com/maven/content/group/public</url>
          <!-- 开启下载release版本,默认开启,可不设置 -->
		  <releases>
			<enabled>true</enabled>
		  </releases>
		  <!-- 开启下载snapshots版本,默认关闭,必须设置 -->
		  <snapshots>
			<enabled>true</enabled>
		  </snapshots>
        </repository>
      </repositories>
    </profile>
  </profiles>
  
  <!-- 只有激活之后才能生效,可以激活多个 -->
  <activeProfiles>
    <activeProfile>nexusProfile</activeProfile>
    <activeProfile>...</activeProfile>
  </activeProfiles>
25、如何保证拿到我们项目源码的同事的maven版本和我们开发时的版本一致问题

利用**mvnw** 这个命令来解决,其全名是maven wrapper,它的原理是在maven-wrapper.properties文件中记录你要使用的maven版本,当其他用户执行mvnw clean 命令时,发现当前用户的maven版本和期望的版本不一致,那么就下载期望的版本,然后用期望的版本来执行mvn命令。

26、Maven多模块项目中,仅执行部分模块操作的技巧
usage: mvn [options] [<goal(s)>] [<phase(s)>]
 
Options:
 -am,--also-make                        If project list is specified, also
                                        build projects required by the
                                        list
 -amd,--also-make-dependents            If project list is specified, also
                                        build projects that depend on
                                        projects on the list
...
 -pl,--projects <arg>                   Build specified reactor projects
                                        instead of all projects
...

解释:
-am:如果 pl 参数存在,就同时构建 pl 参数所列模块依赖的其他模块
-amd:如果 pl 参数存在,就同时构建依赖于 pl 参数所列模块的其他模块
-pl,–projects :构建指定模块,多个模块用逗号(,)分隔

27、Maven多模块项目中,如果子模块下没有pom.xml而是根据项目运行的不同情况而自定义的pom文件名时,如何处理?

在maven中可以通过 -f 来指定要运行的pom文件。

但是,对于有多模块的maven项目,在父项目中只能指定一个子模块名,这样的话,就找不到要执行的pom文件了,幸好Maven想到了这一点,解决方案如下:

	<modules>
		<module>Test_1</module>
		<module>Test_2/pom_01.xml</module>
		<module>Test_2/pom_02.xml</module>
	</modules>

也就是说,Maven支持在module中直接指定要运行的pom文件。

如果要执行Test_2项目中下具体某一个pom时,利用 -pl 指定运行的某一个即可。

28 资源文件中引用POM.XML中的变量—— 非常有用的插件:插件maven-resources-plugin

https://blog.csdn.net/u012501054/article/details/88397182

29 高级玩法:Maven 提速
# 用 4 个线程构建,以及根据 CPU 核数每个核分配 1 个线程进行构建
$ mvn -T 4 clean install
$ mvn -T 1C clean install

推荐链接:
http://www.oschina.net/question/158170_29368
http://blog.csdn.net/evelynhouseba/article/details/19560805
http://blog.csdn.net/evelynhouseba/article/details/19558841
http://www.cnblogs.com/csophys/archive/2012/05/18/2507926.html
http://blog.csdn.net/subuser/article/details/18988813
http://www.cnblogs.com/xdp-gacl/p/4242221.html
http://juvenshun.iteye.com/blog/305865

  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值