2015年12月25日星期五

Maven_002:构建项目

环境: OS X EI Capitan 10.11.2 + JDK 1.8.0_66 + Maven 3.3.9

1. pom.xml

Maven项目的核心是pom.xml文件,POM(Project Object Model)定义了项目的基本信息,描述了项目如何构建,声明了项目的依赖关系,等等。
下面是一个helloworld的pom.xml文件内容:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany</groupId>
    <artifactId>helloworld</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>Hello World</name>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
</project>

(1)modelVersion 指定了当前POM的版本,对于Maven 3 来说,该值只能是4.0.0。
(2)groupId 指定了项目所属的组,一般为某个公司名称或组织名称 + 项目名称,表明当前项目隶属的实际项目,比如org.sonatype.nexus。
(3)artifactId 指定了项目在该组中的唯一标识,一般为实际项目中的一个Maven项目,推荐使用实际的项目名称作为前缀,比如nexus-indexer。
注意,Maven项目和实际项目不一定是一对一的关系,很多实际项目可能对应很多Maven项目。
(4)version 指定了项目的版本。
(5)name 指定了项目的名称,该项不是必须的,但为了可读友好性,还是建议加上该项。
(6)packaging 指定了Maven项目的打包方式,比如 jar(默认方式),war。
(7)calssfier 指定了输出的附属构件,比如 javadoc、sources。附属构件不是项目默认生成的,需要配置相应的插件才可以。

groupId + artifactId + version 定义了一个项目的基本的x、y、z坐标,每一个Maven项目都可以通过这三个坐标来彼此区分。

所有的Maven项目都隐式地继承一个超级POM,对于Maven 3,该文件位于 $MAVEN_HOME/lib/maven-model-builder-x.x.x.jar中的org/apache/maven/model/pom-4.0.0.xml。

2. 项目依赖

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.7</version>
        <scope>test</scope>
    </dependency>
</dependencies>

(1)dependencies 里面可以有多个 dependency,表示项目的依赖。
(2)scope 为依赖范围:
compile(默认选项)表示该依赖对编译、测试、运行的 classpath 都有效,比如 spring-core;
test 表示该依赖只对测试的 classpath 有效,比如 JUnit;
provided  表示该依赖对编译、测试的 classpath 都有效,对运行的 classpath 无效,比如 servlet-api,在编译和测试时需要该依赖,在运行时,因为容器已经提供,因此就不需要了;
runtime 表示该依赖对测试、运行的 classpath 都有效,对编译的 classpath 无效,比如 JDBC驱动,编译时只需要标准的JDBC接口API即可,测试和运行时才需要具体的JDBC驱动;
system 与 provided 方式的依赖一样,只不过指定依赖时,必须通过systemPath显式指定,往往与本机系统绑定,造成不可移植,应慎用。
import 导入依赖范围,该依赖不会对编译、测试、运行的 classpath 有任何实际的影响。
(3)optional
(4)exclusions

关于依赖,还有很多概念需要了解,比如传递性依赖、依赖调解、可选依赖、排除依赖、归类依赖等等,留待以后专文阐述。

要想查看一个Maven项目的依赖,可以运行 mvn:dependency:list 或 mvn:dependency:tree 或 mvn:dependency:analyze。

2. 编译、测试、打包、安装
 (1)mvn clean compile
 (2)mvn clean test
 (3)mvn clean package
该命令会在 target 目录下生成 artifactId + version.jar 文件,也可能是其它类型的文件,比如war文件。
 (4)mvn clean install
为了让其它Maven 项目能够引用该 jar,需要运行该命令将该Maven项目安装到本地库。

3.  使用maven-shade-plugin
我们知道如果要运行.jar中的某个带有Main函数的类,需要在META-INFO目录中创建MANIFEST.MF文件。
文件内容要增加一行:Main-Class: com.juvenxu.mvnbook.helloworld.HelloWorld。
手工增加太麻烦了,为此使用 Maven 插件:maven-shade-plugin。
<plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <configuration>
            <source>1.5</source>
            <target>1.5</target>
          </configuration>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-shade-plugin</artifactId>
          <version>1.2.1</version>
          <executions>
            <execution>
              <phase>package</phase>
              <goals>
                <goal>shade</goal>
              </goals>
              <configuration>
                <transformers>
                  <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                    <mainClass>com.juvenxu.mvnbook.helloworld.HelloWorld</mainClass>
                  </transformer>
                </transformers>
              </configuration>
            </execution>
          </executions>
        </plugin>
</plugins>

使用 maven-compiler-plugin 的目的是为了支持JDK 1.5。

4. 使用 mvn archetype:generate 生成Maven项目骨架 
运行后,将会以交互的方式生成一个Maven项目,目前有1497个Maven项目骨架。
首先输入骨架对应的数字,默认是704,Maven的quickstart项目骨架。
接着输入 groupId、artifactId、version 等值,生成Maven项目。
常用的Maven骨架有maven-archetype-quickstart (Java Project, JAR)、maven-archetype-webapp (Java Web Project, WAR)等等。

5. 使用 mvn archetype:crawl 生成骨架目录文件
1497个Maven骨架太多了,而且不知道选择哪个,可以把所有内容写到一个文件中,然后慢慢查找。
mvn archetype:generate > templates.txt

也可以生成 archetype-catalog 目录,因为实际使用中常用的就是那几个。
运行 mvn archetype:crawl 后,会在~/.m2/responsitory目录下生成archetype-catalog.xml文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<archetype-catalog xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-catalog/1.0.0 http://maven.apache.org/xsd/archetype-catalog-1.0.0.xsd"
    xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-catalog/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <archetypes>
    <archetype>
      <groupId>org.apache.maven.archetypes</groupId>
      <artifactId>maven-archetype-quickstart</artifactId>
      <version>1.1</version>
      <description>quickstart</description>
    </archetype>
  </archetypes>
</archetype-catalog>

把 archetype-catalog.xml 移动到~/.m2目录下。
运行 mvn archetype:generate -DarchetypeCatalog=local,此时只会显示archetype-catalog.xml文件中的骨架。

另外,也可以运行 mvn archetype:generate -DarchetypeCatalog=internal,此时会显示10个内部骨架。

6. 约定优于配置
Maven 的默认约定如下:
(1)源码目录为:src/main/java
(2)编译输出目录为:target/classes
(3)打包方式为:jar
(4)包输出的目录为:target

参考文献:
1. 《Maven 实战》 徐晓斌著
2.  http://www.cnblogs.com/buhaiqing/archive/2012/11/04/2754187.html

没有评论: