项目依赖
项目依赖是指Maven 通过依赖传播、依赖优先原则、可选依赖、排除依赖、依赖范围等特性来管理项目classpath。
依赖传播特性
我们的项目通常需要依赖第三方组件,而第三方组件又会依赖其它组件遇到这种情况Maven会将依赖网络中的所有节点都会加入classpath当中,这就是Maven的依赖传播特性。
例如下面的配置
<!-- 添加spring mvc依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.9.RELEASE</version> </dependency>
项目直接依赖了spring-webmvc 叫直接依赖,而对commons-logging 依赖是通过webmvc传递的所以叫间接依赖。
依赖优先原则
基于依赖传播特性,导致整个依赖网络会很复杂,难免会出现相同组件不同版本的情况。Maven此时会基于依赖优先原则选择其中一个版本。
- 第一原则:最短路径优先。
- 第二原则:相同路径下配置在前的优先。
第一原则示例
<!-- 直接添加commons-logging --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency>
上述例子中commons-logging 通过spring-webmvc 依赖了1.1.3,而项目中直接依赖了1.2,基于最短路径原则项目最终引入的是1.2 版本。
第二原则示例
主要步骤如下所示:
(1)添加一个新工程Project B
(2) 配置Project B 依赖 spring-web.3.2.9-RELEASE
(3)当前工程直接依赖 Project B
配置完之后,当前工程 project A 有两条路径可以依赖 spring-web,选择哪一条 就取决于 对 webmvc 和 Project B的配置先后顺序。
- Project A==> spring-webmvc 5.2.9-RELEASE ==> spring-web 5.2.9-RELEASE
- Project A==> Project B 1.0.SNAPSHOT ==>spring-web.3.2.9-RELEASE
注意:在同一pom文件,第二原则不再适用。如下配置,最终引用的是1.2 版本,而不是配置在前面的1.1.1版本。
<!-- 在1.2 之前添加 commons-logging --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency>
可选依赖
可选依赖表示这个依赖不是必须的。通过在<dependency></dependency>
中添 加<optional>true</optional>
表示,默认是不可选的。可选依赖不会被传递。
排除依赖
即排除指定的间接依赖。通过配置<exclusions></exclusions>
配置排除指定组件。
例如,我们可以使用下面的配置来排除对于spring-web的依赖。
<!-- 排除指定项目 --> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </exclusion> </exclusions>
依赖范围
像junit 这个组件 我们只有在运行测试用例的时候去要用到,这就没有必要在打包的时候把junit.jar 包过构建进去,可以通过Maven 的依赖范围配置<scope></scope>
来达到这种目的。Maven 总共支持以下四种依赖范围:
- compile(默认): 编译范围,编译和打包都会依赖。
- provided: 提供范围,编译时依赖,但不会打包进去。如:servlet-api.jar
- runtime: 运行时范围,打包时依赖,编译不会。如:mysql-connector-java.jar
- test: 测试范围,编译运行测试用例依赖,不会打包进去。如:junit.jar
- system: 表示由系统中classpath指定。编译时依赖,不会打包进去。配合
<systemPath></systemPath>
一起使用。示例:java.home下的tool.jar
system 除了可以用于引入系统classpath 中包,也可以用于引入系统非maven 收录的第三方Jar,做法是将第三方Jar放置在 项目的 lib 目录下,然后配置 相对路径,但因system 不会打包进去所以需要配合 maven-dependency-plugin 插件配合使用。当然,我还是推荐小伙伴们通过 将第三方Jar手动install 到仓库。
接下来,我们就列举几个简单的使用示例。
- system 的通常使用方式
<dependency> <groupId>com.sun</groupId> <artifactId>tools</artifactId> <version>${java.version}</version> <scope>system</scope> <optional>true</optional> <systemPath>${java.home}/../lib/tools.jar</systemPath> </dependency>
- system 另外使用方式 ,将工程内的jar直接引入
<dependency> <groupId>jsr</groupId> <artifactId>jsr</artifactId> <version>3.5</version> <scope>system</scope> <optional>true</optional> <systemPath>${basedir}/lib/jsr305.jar</systemPath> </dependency>
- 通过插件 将system 的jar 打包进去
<plugin> <groupId>org.apache.maven.plugins</groupId>\ <artifactId>maven-dependency-plugin</artifactId> <version>2.10</version> <executions> <execution> <id>copy-dependencies</id> <phase>compile</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/lib</outputDirectory> <includeScope>system</includeScope> <excludeGroupIds>com.sun</excludeGroupIds> </configuration> </execution> </executions> </plugin>
- 手动加入本地仓库
mvn install:install-file -Dfile=mykit-transaction-message.jar -DgroupId=io.mykit -DartifactId=mykit-transaction-message -Dversion=1.0.0-RELEASE -Dpackaging=jar
项目聚合与继承
聚合
聚合是指将多个模块整合在一起,统一构建,避免一个一个的构建。聚合需要个父工程,然后使用 <modules></modules>
进行配置其中对应的是子工程的相对路径。例如下面的配置。
<modules> <module>mykit-dao</module> <module>mykit-service</module> </modules>
继承
继承是指子工程直接继承父工程 当中的属性、依赖、插件等配置,避免重复配置。继承包括如下几种方式。
- 属性继承
- 依赖继承
- 插件继承
注意:上面的三个配置子工程都可以进行重写,重写之后以子工程的为准。
依赖管理
通过继承的特性,子工程是可以间接依赖父工程的依赖,但多个子工程依赖有时并不一至,这时就可以在父工程中加入<dependencyManagement></dependencyManagement>
声明该工程需要的JAR包,然后在子工程中引入。例如下面的配置。
<!-- 父工程中声明 junit 4.12 --> <dependencyManagement> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies> </dependencyManagement> <!-- 子工程中引入 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency>
项目属性
通过 <properties></properties>
配置属性参数,可以简化配置。例如下面的配置。
<!-- 配置proName属性 --> <properties> <projectName>projectName</projectName> </properties>
我们可以在pom.xml文件中使用下面的形式来引入配置的参数。
${projectName}
接下来,我们再来看几个Maven的默认属性,如下所示。
- ${basedir} 项目根目录
- ${version}表示项目版本;
${project.basedir}同${basedir};
${project.version}表示项目版本,与${version}相同;
- ${project.build.directory} 构建目录,缺省为target
- ${project.build.sourceEncoding}表示主源码的编码格式;
- ${project.build.sourceDirectory}表示主源码路径;
- ${project.build.finalName}表示输出文件名称;
- ${project.build.outputDirectory} 构建过程输出目录,缺省为target/classes
项目构建配置
构建资源配置
基本配置示例:
<defaultGoal>package</defaultGoal> <directory>${basedir}/target2</directory> <finalName>${artifactId}-${version}</finalName>
说明:
- defaultGoal:执行构建时默认的goal或phase,如jar:jar或者package等
- directory:构建的结果所在的路径,默认为${basedir}/target目录
- finalName:构建的最终结果的名字,该名字可能在其他plugin中被改变
resources 配置示例
<resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.MF</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*</include> <include>*</include> </includes> <filtering>true</filtering> </resource> </resources>
说明:
- resources:build过程中涉及的资源文件
- targetPath:资源文件的目标路径
- directory:资源文件的路径,默认位于${basedir}/src/main/resources/目录下
- includes:一组文件名的匹配模式,被匹配的资源文件将被构建过程处理
- excludes:一组文件名的匹配模式,被匹配的资源文件将被构建过程忽略。同时被includes和excludes匹配的资源文件,将被忽略。
- filtering:默认false ,true 表示 通过参数 对 资源文件中 的${key} 在编译时进行动态变更。替换源 -Dkey 和pom 中的值 或中指定的properties 文件。