[b]一些常用的命令[/b]

mvn help:effective-pom
用来查看当前工程的完整的pom文件, 比如从父类pom以及默认pom继承的内容

mvn install
将当前的maven构建(项目打包后的文件)安装到本地仓库
mvn install -Dmaven.test.skip=true
跳过测试(同时会跳过test compile)

mvn deploy
将当前的maven构建(项目打包后的文件)安装到远程仓库

mvn archetype:create
这里的archetype是插件, create是目标(goal)

profile命令:
mvn install -DskipTests=true -Penv_test

[b]生命周期[/b]
resource->compile->process-classes->process-test-resources->test-compile->test->prepare-package->package

resources:resources 绑定在resource处理阶段, 用来将src/main/resources下或者任何指定其他目录下的文件copy到输出目录中

resources:testResources 将test下的resources目录或者任何指定其他目录copy到test输出目录下

compiler:testCompile 将测试类编译(包括copy资源文件)

surefire:test 运行测试用例

jar:jar 打jar包

mvn help:describe -Dplugin=exec -Dfull
查看插件的doc文档

查看依赖
mvn dependency:resolve
查看项目依赖情况

mvn dependency:tree
打印出项目的整个依赖树

mvn dependency:analyze
帮助你分析依赖关系, 用来取出无用, 重复依赖的好帮手

mvn install -X
追踪依赖的完整轨迹

[b]测试相关[/b]
默认情况下, 遇到测试失败, surefire:test会中断测试, 如果想忽略测试失败, 继续运行后面的测试, 需要这么配置:

<groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <testFailureIgnore>true</testFailureIgnore>
        </configuration>
</plugin>




从doc文档中看到:Expression: ${maven.test.failure.ignore}


因此也可以从命令行中通过传递参数来实现同样的功能


mvn test -Dmaven.test.failure.ignore=true



mvn install -Dmaven.test.skip=true


跳过单元测试



要跳过测试, 在pom文件也可以这样配置:


<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <skip>true</skip>
        </configuration>
</plugin>




[b]打包输出[/b]


Assembly是一个关于打包输出的插件, 比如这样配置:


<artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
</plugin>

运行命令


mvn assembly:assembly


生成xxxx-1.0-jar-with-dependencies.jar的打包文件, 里面将包含所有的依赖文件



[b]生成项目[/b]


mvn archetype:create


用来生成项目, artifactId和groupId用来指定目标, archetypeArtifactId通过制定类型, 比如 maven-archetype-webapp用该创建一个web项目



在maven中使用jetty容器, 我们需要这样配置一个插件:


<plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>maven-jetty-plugin</artifactId>
</plugin>



mvn jetty:run


用来运行jetty服务器



build配置和dependencies都会被所有的子模块继承



[b]依赖管理[/b]


为了去掉依赖重复, 在多模块pom中将加入所有重复的依赖:


<dependencyManagement>
    <dependencies>



为了去掉版本号这样的重复, 可以这样写:


<properties>
    <hibernate.annotations.version></hibernate.annotations.version>
  </properties>

这样用:


<version>${hibernate.annotations.version}</version>




属性引用


对project属性的引用, 比如这样写:


org.sonatype.mavenbook-${project.artifactId}



直接定义属性:


比如这个属性${foo}=bar, 定义如下:


<properties>
  <foo>bar</foo>
</properties>




可选依赖的配置


<dependency>
     <groupId>net.sf.ehcache</groupId>
     <artifactId>ehcache</artifactId>
     <version>1.4.1</version>
     <optional>true</optional>
   </dependency>



这里举的是关于两种缓存方案的依赖配置, 在编译的时候需要, 但是运行的时候可能不需要.




[b]依赖范围[/b]


compile, test是常用的


需要接的是运行时依赖, 表示在编译时不需要, 在运行时需要, 例子是driver编译的时候是一个api接口依赖, 运行时就需要一个具体的driver class实例了.



感觉只要理解compile和test依赖范围即可, a对b是test依赖, b对c是compile依赖, 那么a对c是test依赖, compile对所有直接依赖下的compile范围都是compile传递依赖, 很绕:(



一个对传递性依赖的排除


<dependency>
  <groupId>org.sonatype.mavenbook</groupId>
  <artifactId>project-a</artifactId>
  <version>1.0</version>
  <exclusions>
    <exclusion>
      <groupId>org.sonatype.mavenbook</groupId>
      <artifactId>project-b</artifactId>
    </exclusion>
  </exclusions>
</dependency>

表示虽然依赖project-a, 但是不想依赖a所依赖的b


这里是排除一个依赖, 添加另外一个依赖


<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate</artifactId>
    <version></version>
    <exclusions>
      <exclusion>
        <groupId>javax.transaction</groupId>
        <artifactId>jta</artifactId>
      </exclusion>
    </exclusions>
  </dependency>
  <dependency>
    <groupId>org.apache.geronimo.specs</groupId>
    <artifactId>geronimo-jta_1.1_spec</artifactId>
    <version>1.1</version>
  </dependency>



使用排除依赖, 一般是一个传递依赖在编译的时候需要, 但是在实际运行环境不需要的时候



dependencyManagement用来在父pom文件中定义公共的依赖, 以及版本号, 是一个集中管理依赖版本的地方



[b]项目关系[/b]


groupId用.分隔, artifactId用-分隔



在继承模块中, maven约定父pom在本地仓库, 或者在当前项目的父目录../pom.xml中可用.可以通过relativePath指定具体的父pom.xml的位置, 一般在多模块中与子模块同级存放父pom.xml, 这时就需要通过relativePath来指定pom.xml了.



从父模块继承要加这样的标签:


<parent>
    <groupId>com.training.killerapp</groupId>
    <artifactId>a-parent</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>




将共同的依赖使用一个pom项目统一组织起来, 并让其他的模块添加对该模块的依赖是一个不错的复用机制.


此时使用的标记是dependencies而不是dependencyManagment了.比如这样写:


<groupId>org.sonatype.mavenbook</groupId>
  <artifactId>persistence-deps</artifactId>
  <version>1.0</version>
  <packaging>pom</packaging>
  </dependencies>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>${mysqlVersion}</version>
    </dependency>
  </dependencies>
  <properties>
    <mysqlVersion>(5.1,)</mysqlVersion>
  <properties>

对该pom的依赖需要这样写:


<dependency>
      <groupId>org.sonatype.mavenbook</groupId>
      <artifactId>persistence-deps</artifactId>
      <version>1.0</version>
      <type>pom</type>
    </dependency>



多了一个type标记



[b]一个简单的多模块+继承应用[/b]


server-side包含web-apps和server-lib两个子模块, 并且是二者的父模块, web-apps依赖server-lib模块(里面定义了所有的web-app所要依赖的jar包), web-apps 是个多模块, web-client, web-admin是他的两个子模块, 同时具有父子关系. 这样设计的结果将导致web-client和web-admin的定义将非常小巧, 简洁


POM继承十分有用,但它可能被滥用。当然在需要共享依赖和配置的时候,父子关联需要被使用。但当两个项目截然不同的时候使用父子关联是不明智的。



[b]生命周期[/b]


在执行clean之前的pre-clean中指定需要执行的插件目标, 这个配置没看懂:(



由于生命周期阶段会绑定对应的插件, 因此可以对对应的插件进行定制, 达到定制声明周期的目的


比如对clean插件的定制:


<plugin>
        <artifactId>maven-clean-plugin</artifactId>
        <configuration>
          <filesets>
            <fileset>
              <directory>target-other</directory>
              <includes>
                <include>*.class</include>
              </includes>
            </fileset>
          </filesets>
        </configuration>
      </plugin>




[b]资源处理周期[/b]


resources:resources会将src/main/resources下的文件内容复制到target/classes中. 同时还可以在copy之前做一些过滤替换工作.


关于过滤替换, 如果有这样一个文件:


<service>
  <!-- This URL was set by project version 0.6-SNAPSHOT -->
  <url>${jdbc.url}</url>
  <user>${jdbc.username}</user>
  <password>${jdbc.password}</password>
</service>

属性配置文件如下:


jdbc.url=jdbc:hsqldb:mem:mydb


jdbc.username=sa


jdbc.password=


过滤默认是不开启的, 需要配置一下:


<build>
  <filters>
    <filter>src/main/filters/default.properties</filter>
  </filters>
  <resources>
    <resource>
      <directory>src/main/resources</directory>
      <filtering>true</filtering>
    </resource>
  </resources>
</build>



src/main/resources是默认的资源文件目录, 但是也可以指定其他目录:


<resources>
    <resource>
      <directory>src/main/resources</directory>
    </resource>
    <resource>
      <directory>src/main/xml</directory>
    </resource>
    <resource>
      <directory>src/main/images</directory>
    </resource>
  </resources>



对不同的资源进行分门别类的处理, 这样方便我们对不同的资源采用不同的过滤处理, 比如这样写:


<resource>
      <filtering>true</filtering>
      <directory>/src/main/command</directory>
      <includes>
        <include>run.bat</include>
        <include>run.sh</include>
      </includes>
      <targetPath>/</targetPath>



会将指定目录下的run.bat, 文件复制到指定的目录(targetPath)中



[b]编译周期[/b]


maven默认的编译(compile:compile)版本是1.3, 运行平台版本是1.1, 现在一般需要配置成1.5以上版本


<plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>



上面是指定插件的版本, 如果要制定目标的版本, 需要将configuration元素放到execution元素下.


如果你想要存储项目的源码至src/java而非src/main/java,让构建输出至classes而非target/classes,你可以覆盖定义在超级POM中的sourceDirectory的默认值(不推荐这样做, 我们始终应该遵循"约定优于配置"的原则)。


<build>
  ...
  <sourceDirectory>src/java</sourceDirectory>
  <outputDirectory>classes</outputDirectory>
  ...
</build>




[b]Test周期[/b]


绑定的surefire:test, 默认情况下, 如果测试失败, 停止构建, 如果希望继续构建, 需要这样设置:


<plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-surefire-plugin</artifactId>
     <configuration>
       <testFailureIgnore>true</testFailureIgnore>
     </configuration>
    </plugin>




[b]profile[/b]


通过profile可以针对特定的环境来定制不同的artifact, 比如这样写来覆盖compile插件的默认配置:


<profiles>#
    <profile>
      <id>production</id>#
      <build>#
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
              <debug>false</debug>#
              <optimize>true</optimize>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>



使用profile的命令行用法:


mvn clean install -Pproduction -X


可以根据某种条件激活对应 profile, 比如根据jdk版本包含指定的模块:


<profile>
      <id>jdk16</id>
      <activation>
        <jdk>1.6</jdk>
      </activation>
      <modules>
        <module>simple-script</module>
      </modules>
    </profile>



activation元素列出了所有激活profile需要的条件, 比如下面的配置:


<activation>
        <activeByDefault>false</activeByDefault>#
        <jdk>1.5</jdk>#
        <os>
          <name>Windows XP</name>#
          <family>Windows</family>
          <arch>x86</arch>
          <version>5.1.2600</version>
        </os>
        <property>
          <name>mavenVersion</name>#
          <value>2.0.5</value>
        </property>
        <file>
          <exists>file2.properties</exists>#
          <missing>file1.properties</missing>
        </file>
      </activation>



通过属性来激活:


<activation>
        <property>
          <name>!environment.type</name>
        </property>
      </activation>



可以将profile从pom.xml中拆分出来, 单独的放在profiles.xml文件中


除了可以在pom, pom外部设置profile外, 还可以在setting中设置profile, 可以将一些私密的信息设置在自己的settging.xml中


通过profile指定属性, 比如有一个envClassifier属性:


<build>
    <plugins>
      <plugin>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
          <classifier>${envClassifier}</classifier>
        </configuration>
      </plugin>
    </plugins>
  </build>



那么可以有这样的profile来指定一个envClassifier:


<profile>
      <id>windows</id>
      <activation>
        <os>
          <family>windows</family>
        </os>
      </activation>
      <properties>
        <envClassifier>win</envClassifier>
      </properties>
    </profile>




[b]Assembly[/b]


简单的说就是打包方式, 比如jar, ear, war都是不同的Assembly, 比如希望打包的文件中带有源码, api文档等都需要定制Assembly.


一些Assembly描述符(指定打包包含内容)


bin:最小打包文件


jar-with-dependencies:包含所有依赖


project:包含所有的项目信息, 可以直接构建maven项目, 因此里面会包含pom.xml文件, 如果是个eclipse工程, 还会包含eclipse工程配置文件


src:包含源码


将项目打包一份儿, 发给其他人的命令:


mvn -DdescriptorId=project assembly:single


配置一个将一个工程打包成一个可运行的jar文件(跟package阶段绑定):


<plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.2-beta-2</version>
        <executions>
          <execution>
            <id>create-executable-jar</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
            <configuration>
              <descriptorRefs>
                <descriptorRef>
                  jar-with-dependencies
                </descriptorRef>
              </descriptorRefs>
              <archive>
                <manifest>
                  <mainClass>org.sonatype.mavenbook.App</mainClass>
                </manifest>
              </archive>
           </configuration>
          </execution>
        </executions>
      </plugin>




写在顶层pom中pluginManagement(dependencyManagement)标签下的配置只是定义, 并不会被使用.子模块中需要显式的激活, 比如这样写:


<pluginManagement>
      <plugins>
        <plugin>
          <artifactId>maven-assembly-plugin</artifactId>
          <version>2.2-beta-2</version>
          <executions>
            <execution>
              <id>create-project-bundle</id>
              <phase>package</phase>
              <goals>
                <goal>single</goal>
              </goals>
              <configuration>
                <descriptorRefs>
                  <descriptorRef>project</descriptorRef>
                </descriptorRefs>
              </configuration>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </pluginManagement>



子模块的激活配置:


<plugins>
    <plugin>
      <artifactId>maven-assembly-plugin</artifactId>
    </plugin>
  </plugins>




[b]maven插件[/b]


一个插件包含一个描述符和多个mojo, 可以将mojo理解为目标, 比如compile:compile对应的是compile插件的CompileMojo类


一个描述符用来告诉maven, 一个插件的各种配置他在jar文件中的META-INFO/maven/plugin.xml, 当maven加载一个插件的时候, 它首选读取该描述文件, 然后去找Mojo以及资源等信息.