目前工作中使用的是Maven进行Java代码的项目管理,Maven主推的是集中式的项目管理方式,就是将Web工程中依赖的jar包放在统一路径下进行集中式的管理。


下面简单说下Maven管理的工程的pom文件的常见使用方法和规则,Maven管理的项目依赖是以xml文件格式(文件名:pom.xml)放在工程的根目录下面的。首先我们看一个简单的pom文件来了解下基本的pom.xml格式,见下面xml文件内容。

</pre><p></p><p><pre name="code" class="html"><?xml version="1.0" encoding="UTF-8"?>
<!-- Maven POM  -->
<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/maven-v4_0_0.xsd">

    <!-- 标记工程的父工程, 可以不填写 -->
    <parent>
        <groupId>com.sample</groupId>
        <artifactId>parent</artifactId>
        <version>1.0.1</version>
    </parent>

    <!-- 描述本工程的信息:groupId和artifactId,名字,打包方式() ,及版本-->
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.alibaba.webx</groupId>
    <artifactId>tutorial1</artifactId>
    <name>My Simple Webx Application</name>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>


    <!-- 文件中后面需要用的一些变量,放在这里是为了突出和管理 -->
    <properties>
        <java.version>1.6</java.version>
        <java.encoding>UTF-8</java.encoding>
        <webx-version>3.2.4</webx-version>
    </properties>

    <!--  工程如果有多个子工程构成,则需要声明子工程的信息 -->
    <modules>
        <module>sample-biz</module>
        <module>sample-common</module>
        <module>sample-config</module>
    </modules>

    <!-- 工程依赖的二方或三方包信息 -->
    <dependencies>
        <dependency>
            <groupId>com.alibaba.citrus</groupId>
            <artifactId>citrus-webx-all</artifactId>
        </dependency>
    </dependencies>

    <!-- 一般有多个子工程时在这里声明第三方的依赖信息,子工程在依赖的时候就不需要声明依赖的版本信息,这也是maven集中式的项目管理理念的一个体现。避免多个子pom依赖的jar版本冲突,并同统一管理依赖版本信息,一般子pom文件中不需要这个标签 -->
    <dependencyManagement>
        <dependencies>
            <!-- ================================================= -->
            <!-- Webx框架依赖 -->
            <!-- ================================================= -->
            <dependency>
                <groupId>com.alibaba.citrus</groupId>
                <artifactId>citrus-webx-all</artifactId>
                <version>${webx-version}</version>
            </dependency>
            <!-- ================================================= -->
            <!-- 日志及相关依赖(用slf4j+logback代替jcl+log4j) -->
            <!-- ================================================= -->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>1.7.5</version>
                <scope>test</scope>
            </dependency>

            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>1.7.5</version>
                <exclusions>
                    <exclusion>
                        <groupId>com.sample.forest</groupId>
                        <artifactId>smaple.client</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>


    </dependencyManagement>

    <!-- 工程文件打包或测试的时候需要的一些插件配置 -->
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
        <pluginManagement>
            <plugins>
                <plugin>
                    <artifactId>maven-antrun-plugin</artifactId>
                    <version>1.7</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

</project>






在前面的简单的pom.xml文件中,基本每部分的内容我都做了备注解释每个标签的意义及使用场景(主要是子工程和父工程中),现在主要说明下其中的附加功能和常见的问题。

1.依赖范围 scope 标签

<dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-api</artifactId>
   <version>1.7.5</version>
   <scope>test</scope>
</dependency>

<scope>标签值的选项有:

  1. compile:默认的
  2. test:运行单元测试引入依赖,打包时不会依赖
  3. provided:编译时依赖,不会被打包。如依赖容器的某个jar,只有运行的时候才使用到,编译期间无需应用容器,这种场景下使用这个值
  4. runtime:运行时依赖
  5. system:指定为这个值的时候需要添加依赖的jar的具体路径,使用场景和配置见 http://agile-boy.iteye.com/blog/56698


2.依赖版本限制


<version>[3.8,4.0)</version>  要求的依赖版本>=3.8且<4.0
 <version>[,3.8.1]</version>  要求的依赖版本<=3.8.1
 <version>[3.8.1]</version>  要求必须是3.8.1版本,如果不是的话会构建失败,提示版本冲突。原来的写法<version>3.8.1</version>的意思是所有版本都可以,但最好是3.8.1


3.间接依赖的排除


比如:依赖的jar里面间接依赖一个不想依赖的工程 smaple.client ,这个时候可以主动排查间接依赖的jar,具体配置如下


<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.5</version>
    <exclusions>
       <exclusion>
          <groupId>com.sample.forest</groupId>
          <artifactId>smaple.client</artifactId>
       </exclusion>
    </exclusions>
</dependency>



4.maven的jar版本选择策略


  • 优先选择主pom中dependencyManagement声明的版本
  • 如果没有声明则选择依赖路径最短的jar版本
  • 如果路径相同有严格区间限制的优先
  • 若路径相同且无严格区间限制则先入为主。


总结:maven的项目依赖管理极大的解放了开发的劳动力,让开发将主要精力放在业务开发和业务逻辑实现上;但是最大的问题就是jar冲突导致的各种NoSuchMethod,ClassNotFound等等类似的错误,只能靠开发在引入新的jar包时注意避免引入冲突的jar。另外根据maven的jar版本选择策略,工程中明确使用的jar最好指定版本,而不是依赖于已有的间接依赖。