Jade Dungeon

Maven配置

配置

环境变量M2_HOME指向安装根目录。

模板的位置在:$M2_HOME/conf/settings.xml

配置文件位置:~/.m2/conf/settings.xml

检查安装是否成功:

mvn -v

如果有输出版本信息就安装正确。

查看帮助,如果是第一次运行就会下载到本地仓库:

mvn help:system

HTTP代理

官方中央库:repo1.maven.org

如果要用代理,在settings.xml中加上:

<proxies>
	<proxy>
		<id>my-proxy</id>
		<active>true</active>
		<protocol>http</protocol>
		<host>218.14.227.197</host>
		<port>3128</port>
		<!--
			<username>username</username>
			<password>p@ssw0rd</password>
			<nonProxyHosts>repository.mycom.com|*.google.com</nonProxyHosts>
		-->
	</proxy>
	<proxy>
		...
	</proxy>
</proxies>

proxy可以有多个,第一个是默认的。

maven属性

内置属性

  • ${basedir}
  • ${version}

POM属性

  • ${project.groupId}
  • ${project.artifactId}
  • ${project.version}
  • ${project.build.finalName}:project.artifactId-project.version
  • ${project.build.sourceDirectory}:src/main/java
  • ${project.build.testSourceDirectory}:src/test/java
  • ${project.build.directory}:target
  • ${project.outputDirectory}:target/classes
  • ${project.testOutputDirectory}:target/test-classes

其他属性

  • settings.xml中的值,如:${settings.localRepository}是本地仓库。
  • Java系统属性:如user.home
  • 系统环境变量:如${env.JAVA_HOME},通过mvn help:system查看

XML中定义属性

<project>
	...
	<properties>
		<myprop>hello</myprop>
	</properties>
	...
</project>









建立工程

配置工程目录结构

如果不用默认的目录结构,要自定义的话:

<build>
     <!-- Java 源代码的路径配置 -->
     <sourceDirectory>src/main/java</sourceDirectory>
     <scriptSourceDirectory>src/main/scripts</scriptSourceDirectory>
     <!-- 测试代码的路径配置 -->
     <testSourceDirectory>src/test/java</testSourceDirectory>
     <!-- 源码编译后的 class 文件的路径配置 -->
     <outputDirectory>target/classes</outputDirectory>
     <!-- 测试源码编译后的 class 文件的路径配置 -->
     <testOutputDirectory>target/test-classes</testOutputDirectory>
     <plugin> .... </plugin>
 </build>

Archetype生成项目骨架

列出各种工程的模块,然后选一个:

mvn archetype:generate

先会让先生成框架工具的版本,就用默认最新的maven-archetype-quickstart就可以了 。然后按向导输入信息。

包管理

坐标

  • groupId
  • artifactId
  • version
  • packaging:默认为jar
  • classifier:不可配置,由附加插件生成。如一个包可以有附加的源代码包或文档包。

依赖配置

依赖 编译时需要 测试时需要 运行时需要 例子
compile Y Y Y spring-core
test   Y   JUnit
provided Y Y   servlet-api
runtime   Y Y JDBC的实现,如:MySQL-driver
system Y Y   与本机系统绑定不通过Maven仓库依赖

system级别的依赖必须通过systemPath元素显式指定依赖文件的路径。systemPath元素 可以引用环境变量,如:

<dependency>
	<groupId>javax.sql</groupId>
	<artifactId>jdbc-stdext</artifactId>
	<version>2.0</version>
	<scope>system</scope>
	<systemPath>${java.home}/lib/rt.jar</systemPath>
</dependency>

传递依赖

  compile test provided runtime
compile compile     runtime
test test     test
provided provided   provided provided
runtime runtime     runtime

例子:

  • greenmail直接compile依赖javax.mail(上表第一列)
  • 我们的MailApp直接test依赖greenmail(上表第二行)
  • 那么MailApp对javax.mail的依赖就是test(交叉位置)

可选依赖

比如某工具包对于JDBC驱动实现,有MySQL和PostgreSQL等。但其他应用引用这个工具包时 ,只会依赖一种数据库:

<dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.10</version>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<version>8.4-701.jdbc3</version>
			<optional>true</optional>
		</dependency>
	</dependencies>

其他项目在用到上面这个包时,如果用的是mysql,就要显式声明依赖 mysql-connector-java

可选依赖是一个不推荐的实现,违反了单一性原则。推荐的做法是对MySQL和PostgreSQL 分别搞两个包。

优化依赖

  • 查看已经解析的依赖:mvn dependency:list
  • 树形展示依赖:mvn dependency:tree
  • 分析依赖:mvn dependency:analyze,显示结果:
    • Used undeclared dependencies,已经用到,没有显式声明。应该显式声明出来。
    • unused declared dependencies,声明了但是没有用。注意只是没有编译依赖, 可能会有运行和测试依赖,所以不一字能去掉。

导出包

把maven项目中的jar包复制出来,导出到默认目录targed/dependency

dependency:copy-dependencies

指定输出的目录:

dependency:copy-dependencies -DoutputDirectory=lib

指定信赖的级别:

dependency:copy-dependencies -DoutputDirectory=lib -DincludeScope=compile

仓库

本地仓库

~/.m2/settings.xml中定义本地仓库的位置:

<settings>
	<localRepository>/myfolder/m2/repository</localRepository>
</settings>

把项目发布到本地仓库:mvn clean install

打包时跳过单元测试:

mvn install -Dmaven.test.skip=true

远程仓库

中央仓库

$M@_HOME/lib/maven-model-builder-3.0.jar中配置文件 org/apache/maven/model/pom-4.0.0.xml是所有Maven项目都会继承的超级POM,里面 定义了中央仓库的信息:

...
<repository>
	<id>central</id>
	<url>http://repo1.maven.org/maven2</url>
	...
</repository>
...

配置远程仓库

比如要增加JBOSS的仓库,那么在pom.xml中加上:

<project>
	...
	<repositories>
		<repository>
			<id>jboss</id>
			<name>JBoss Repository</name>
			<url>http://repository.jboss.com</url>
			<releases>
				<enabled>true</enabled>
			</releases>
			<snapshots>
				<enabled>true</enabled>
				<updatePolicy>daily</updatePolicy>
				<checksunPolicy>ignore</checksunPolicy>
			</snapshots>
			<layout>default</layout>
		</repository>
	</repositories>
	...
</project>
  • id必须唯一,重名了会被覆盖。如:定义了一个叫central的就会把maven默认的 中央库给替换掉。
  • release是否下载正式发布的版本。
  • snapshots是否下载开发中的快照版本,如果为true,就还要另外指定:
    • updatePolicy:检查更新频率:neverdailyinterval: x每隔x分钟、 always每次构建都检查。
    • checksumPolicy:检验文件:ignorewarnfail

远程仓库认证

仓库信息可以直接放在pom.xml中,但认证信息一定要放在settings.xml里。 以一个id为my-proj的仓库的认证信息为例:

<settings>
	...
	<servers>
		<server>
			<id>my-proj</id>
			<username>repo-user</username>
			<password>repo-pwd</password>
		</server>
	</servers>
	...
</settings>

部署到远程仓库

配置pom.xml中的distributionManagement元素:

<project>
	...
	<distributemanagement>
		<repository>
			<id>proj-releases</id>
			<name>Proj Release Repository</name>
			<url>http://192.168.1.100/content/repository/proj-releases</url>
		</repository>
		<snapshotRepository>
			<id>proj-snapshots</id>
			<name>Proj Snapshot Repository</name>
			<url>http://192.168.1.100/content/repository/proj-snapshots</url>
		</snapshotRepository>
	</distributemanagement>
	...
</project>

这里分别定义了快照和发布版本的库,要布署到远程库使用命令:

mvn clean deploy

包的版本

Range Meaning
1.0 x >= 1.0 推荐 1.0 ,但也可以用1.0以上的版本
(,1.0] x <= 1.0
(,1.0) x < 1.0
[1.0] x == 1.0
[1.0,) x >= 1.0
(1.0,) x > 1.0
(1.0,2.0) 1.0 < x < 2.0
[1.0,2.0] 1.0 <= x <= 2.0
(,1.0],[1.2,) x <= 1.0 or x >= 1.2. Multiple sets are comma-separated
(,1.1),(1.1,) x != 1.1

快照版本

虽然更新快照的频率可以通过updatePolicy控制,但也可以强制检查更新。例:

mvn clean update -U

Maven会检查仓库的元数据groupid/artifactId/version/maven-metadata.xml

<metadata>
	<versioning>
		<groupId>org.sonatype.nexus</groupId>
		<artifactId>nexus</artifactId>
		<version>1.4.2-SNAPSHOT</version>
		<snapshot>
			<timestamp>20091214.221414</timestamp>
			<buildNumber>13</buildNumber>
		</snapshot>
	</versioning>
</metadata>

如果元数据出错了,可能就无法解析,这时就要通过手工或工具(如Nexus)修复。

LAST 和 RELEASE 版本

Maven 3 已经不支持 LAST 和 REALSE 版本。如果不指定包的版本,会默认使用最新的 版本,但在实践中不推荐这样做。

镜像

http://maven.net.cn/content/groups/public/就是中央库在中国的一个镜像。可以 用来替换中央库:

<settings>
	...
	<mirrors>
		<mirror>
			<id>maven.net.cn</id>
			<name>one of the central mirrors in chia</name>
			<url>http://maven.net.cn/content/groups/public</url>
			<mirrorOf>central</mirrorOf>
		</mirror>
	</mirrors>
	...
</settings>

central表示任何对中央库的请求会被转到这里。

私服作为镜像

例:用一个私服作为所有远程仓库的镜像:

<settings>
	...
	<mirrors>
		<mirror>
			<id>maven.net.cn</id>
			<name>one of the central mirrors in chia</name>
			<url>http://maven.net.cn/content/groups/public</url>
			<mirrorOf>central</mirrorOf>
		</mirror>
	</mirrors>
	...
</settings>
  • <mirrorOf>*</mirrorOf>:匹配所有的远程仓库。
  • <mirrorOf>external:*</mirrorOf>:除了本机上使用file://协议的
  • <mirrorOf>repo1,repo2</mirrorOf>:匹配指定
  • <mirrorOf>#,! repo1</mirrorOf>:匹配除了指定以外的

注意镜像是屏蔽远程对象的,所以镜像服务器坏了就连不了了。

仓库搜索服务

生命周期

maven把构建过程分成大周期,每个周期下又有多个阶段。

  • clean:前期清理与准备工作。
    • pre-clean
    • clean
    • post-clean
  • default:编译与生成包。
    • validate
    • initialize
    • generate-sources
    • process-sources
    • generate-resources
    • process-resources
    • compile
    • process-classes
    • generate-test-sources
    • process-test-sources
    • generate-test-resource
    • process-test-resource
    • test-compile
    • process-test-classes
    • test
    • prepare-package
    • package
    • pre-integration-test
    • integration-test
    • post-integration-test
    • verify
    • install
    • deploy
  • site:生成与应用相关的文档。
    • pre-site
    • site
    • post-site
    • site-deploy

生命周期与插件的绑定

maven本身不进行构建操作,而是通过在不同时间调用不同的插件完成构建工作。

各阶段的默认绑定

clean:

生命阶段 插件目标
pre-clean  
clean maven-clean-plugin:clean
post-clean  

site:

生命阶段 插件目标
pre-site  
site maven-site-plugin:site
post-site  
site-deploy maven-site-plugin:deploy

default:

生命阶段 插件目标 任务
process-sources maven-resources-plugin:resources 复制资源文件到主输出目录
compiles maven--plugin:compile 编译程序文件到主输出目录
generate-test-sourcess maven-resources-plugin:testResources 复制测试资源文件到测试主输出目录
test-compiles maven--plugin:testCompile 编译测试程序文件到测试主输出目录
tests maven-surefire-plugin:test 执行测试用例
packages maven-jar-plugin:jar 创建jar包
installs maven-install-plugin:install 部署到本地仓库
deploys maven-deploy-plugin:deploy 部署到过程仓库

自定义绑定

比如把源代码打包的任务没有默认绑定,这时手动绑定到default的verify阶段:

<build>
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-source-plugin</artifactId>
			<version>2.1.1</version>
			<executions>
				<execution>
					<id>attach-sources</id>
					<phase>verify</phase>
					<goals>
						<goal>jar-no-fork</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build>

executions下的每个execution子元素都可以配置一个任务。这里的attach-sources任务 ,phase指定阶段为verify,goals指定目标为jar-no-fork。执行:

mvn verify

就算是删除掉phase一行,也有默认的绑定阶段。可以通过以下命令查看插件目标的 默认绑定阶段:

mvn help:describe -Dplugin=org.apache.maven.plugins:maven-source-plugin:2.1.1- -Ddetail

插件配置

命令行参数配置

命令行参数配置的方式是:-D参数=值

有些参数适合从命令行配置,比如maven-surefire-plugin当maven.test.skip=true时 跳过测试:

mvn install -Dmaven.test.skip=true

POM文件中全局配置

configuration下。比如scala-maven-plugin,指定编译参数和运行参数:

<plugin>
	<groupId>net.alchim31.maven</groupId>
	<artifactId>scala-maven-plugin</artifactId>
	<configuration>
		<scalaVersion>${scala.version}</scalaVersion>
		<jvmArgs>
			<jvmArg>-client</jvmArg>
			<jvmArg>-Xms64m</jvmArg>
			<jvmArg>-Xmx1024m</jvmArg>
		</jvmArgs>
		<launchers>
			<launcher>
				<id>foo</id>
				<mainClass>example.ScalaAppExample</mainClass>
				<args>
					<arg>Hello</arg>
					<arg>World</arg>
				</args>
			</launcher>
		</launchers>
	</configuration>
	...
</plugin>

POM中任务配置

execution下。比如scala-maven-plugin,指定运行任务:

<plugin>
	<groupId>net.alchim31.maven</groupId>
	<artifactId>scala-maven-plugin</artifactId>
	...
	<executions>
		<execution><!-- do "scala:compile" when "compile" -->
			<id>compile-scala</id>
			<phase>compile</phase>
			<goals>
				<goal>compile</goal>
			</goals>
		</execution>
		<execution><!-- do "scala:testCompile" when "test-compile" -->
			<id>compile-scala-test</id>
			<phase>test-compile</phase>
			<goals>
				<goal>testCompile</goal>
			</goals>
		</execution>
	</executions>
</plugin>

使用maven-help-plugin插件来描述插件

mvn help:describe -Dplugin=org.apache.maven.plugins:maven-compiler-plugin:2.1.1 -Ddetail

可以简化只坐标:

mvn help:describe -Dplugin=compiler

还可以指定目标,比如查看与compile目标相关:

mvn help:describe -Dplugin=compiler -Dgoal=compile

聚合和继承

聚合

有很多个工程不用一个一个构建,让一个工程聚集其他多个工程,然后一起构建。

  • packaging类型必须为pom
  • module指定聚合的工程
<project>
	<modelVersion>4.0.0</modelVersion>

	<groupId>jade.jadeutils</groupId>
	<artifactId>jadeutils-parent</artifactId>
	<version>2.0.0</version>
	<packaging>pom</packaging>
	<name>jade utils parent</name>

	<modules>
		<module>../jadeutils-base</module>
		<module>../jadeutils-cache</module>
		<module>../jadeutils-dao</module>
		<module>../jadeutils-web</module>
		<module>../jadeutils-image</module>
		<module>../jadeutils-sandtable</module>
		<module>../jadeutils-cdn</module>
	</modules>
	
	...
</project>

继承

  • packaging类型必须为pom
  • 子项目中通过parent指定父项目
  • relativePath可以在不通过仓库的情况下找到父pom。如果省略就一定要在本地仓库 里有父项目。
	<parent>
		<groupId>jade.jadeutils</groupId>
		<artifactId>jadeutils-parent</artifactId>
		<version>2.0.0</version>
		<relativePath>../jadeutils-parent/pom.xml</relativePath>
	</parent>

可以继承的元素有:

  • groupId
  • version
  • description
  • organization
  • inceptionYear
  • url
  • developers
  • contributors
  • distributionManagement
  • issueManagement
  • ciManagement:项目持续集成系统信息
  • scm:版本管理系统
  • mailingLists
  • properties:自定义的Maven属性
  • dependencies
  • dependencyManagement
  • repositories
  • build
  • reporting

父项目中进行依赖管理:

<dependencyManagement>
	<dependencies>
		<dependency> <!-- common log -->
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-jcl</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
		<dependency> <!-- jdk log -->
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-jdk14</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
	</dependencies>
</dependencyManagement>

父项目中进行插件管理:

<project>
	...
	<build>
		<pluginManagement>
			<plugins>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-compiler-plugin</artifactId>
					<version>3.0</version>
					<configuration>
						<source>1.8</source>
						<target>1.8</target>
						<encoding>utf8</encoding>
					</configuration>
				</plugin>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-resources-plugin</artifactId>
					<configuration>
						<encoding>UTF-8</encoding>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>
	...
</project>

反应堆

用户开发的不同子模块之间相互依赖,形成一个依赖的反应堆。形式应该是一个 有向非循环图(Directed Acyclic Graph, DAG)。如果有环形依赖Maven会报错。

裁剪反应堆

通过mvn -h查看帮助。

指定构建的模块,参数-pl--projects,用逗号分隔:

vmcn clean install -pl account-email, account-persist

构建指定模块和它所依赖的模块,参数-am--also-make

vmcn clean install -pl account-email -am

构建指定模块和依赖于它的模块,参数-amd--also-make-dependents

vmcn clean install -pl account-parent -amd

在反应堆构建顺序上指定从哪个模块开始构建,参数rfresume-from

vmcn clean install -rf account-parent -amd

可以把条件组合起来:

vmcn clean install -pl account-parent -amd -rf account-email

编译

任务

  • clean:clean
  • compiler:compiler
  • compiler:testCompile

clean:clean为例,代表的意思是clean插件的clean目标,其他类似。

支持Java 5

默认只支持Java 1.3,要配置才能支持更高版本:

	<build>
		<pluginManagement>
			<plugins>

				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-compiler-plugin</artifactId>
					<version>3.0</version>
					<configuration>
						<source>1.7</source>
						<target>1.7</target>
						<encoding>utf8</encoding>
					</configuration>
				</plugin>

		</pluginManagement>
	</build>

打包

任务

  • package:默认生成的是Jar包。
  • install:install

MANIFEST.MF

如果是可运行的带main()方法的jar包,还要生成对应的MANIFEST.MF文件:

<project ... >
	...
	<build>
		...
		<plugins>
			...
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>2.3</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
          </execution>
        </executions>
				<configuration>
					<transformers>
						<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
							<manifestEntries>
								<Main-Class>example.ScalaAppExample</Main-Class>
								<Build-Number>123</Build-Number>
							</manifestEntries>
						</transformer>
					</transformers>
				</configuration>
      </plugin>
		</plugins>
		...
</project>

manifestEntries里以key-value形式添加内容。以上为例就是:

  • Main-Class: example.ScalaAppExample
  • Build_number: 123

这样会生成两个jar包:

  • hello-1.0-SNAPSHOT.jar:有Main-Class可运行。
  • original-hello-1.0-SNAPSHOT.jar:没有Main-Class,不可运行。

运行

运行Java的main方法

Without arguments:

mvn exec:java -Dexec.mainClass="com.vineetmanohar.module.Main"  

With arguments:

mvn exec:java -Dexec.mainClass="com.vineetmanohar.module.Main" -Dexec.args="arg0 arg1 arg2"  

With runtime dependencies in the CLASSPATH:

mvn exec:java -Dexec.mainClass="com.vineetmanohar.module.Main" -Dexec.classpathScope=runtime  

Running in a phase in pom.xml

You can also run the main method in a maven phase. For example, you can run the CodeGenerator.main() method as part of the test phase.

<build>  
 <plugins>  
  <plugin>  
   <groupId>org.codehaus.mojo</groupId>  
   <artifactId>exec-maven-plugin</artifactId>  
   <version>1.1.1</version>  
   <executions>  
    <execution>  
     <phase>test</phase>  
     <goals>  
      <goal>java</goal>  
     </goals>  
     <configuration>  
      <mainClass>com.vineetmanohar.module.CodeGenerator</mainClass>  
      <arguments>  
       <argument>arg0</argument>  
       <argument>arg1</argument>  
      </arguments>  
     </configuration>  
    </execution>  
   </executions>  
  </plugin>  
 </plugins>  
</build>  

Running in a profile in pom.xml

You can also run the main method in a different profile. Simply wrap the above config in the <profile> tag.

<profiles>  
 <profile>  
  <id>code-generator</id>  
  <build>  
   <plugins>  
    <plugin>  
     <groupId>org.codehaus.mojo</groupId>  
     <artifactId>exec-maven-plugin</artifactId>  
     <version>1.1.1</version>  
     <executions>  
      <execution>  
       <phase>test</phase>  
       <goals>  
        <goal>java</goal>  
       </goals>  
       <configuration>  
        <mainClass>com.vineetmanohar.module.CodeGenerator</mainClass>  
        <arguments>  
         <argument>arg0</argument>  
         <argument>arg1</argument>  
        </arguments>  
       </configuration>  
      </execution>  
     </executions>  
    </plugin>  
   </plugins>  
  </build>  
 </profile>  
</profiles>  

常用任务

  • resources:resources
  • resources:testResources

JVM参数

参数加在MAVEN_OPTS中,比如内存大小的分配:

set MAVEN_OPTS= -Xms128m -Xmx512m
#

初始化

mvn help:system