Maven初探

    本文描述了如何使用maven构建一个简单的Hello World项目

1.编写POM

    Maven项目的核心是pom.xml(Project Object Model),pom定义了项目的基本信息,用于描述项目如何构建,声明项目依赖等等。先为Hello World项目编写一个简单的pom.xml。

    首先创建一个hello-world的文件夹,在该目录下新建一个名为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.juvenxu.mvnbook</groupId>
  <artifactId>hello-world</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>Maven Hello World Project</name>
  </project>

    modelVersion指定当前pom模型的版本,对于Maven2及Maven3来说,它只能是4.0.0。这段xml代码中最重要的是groupId、artifactId和version三行。这三个元素定义了一个项目基本的坐标。

    groupId定义了项目属于哪个组,这个组往往和项目所在的组织或公司存在关联。如果你的公司是mycom,有一个项目叫myapp,那么groupId就应该是com.mycom.myapp。

    artifactId定义了当前Maven项目在组中唯一的ID,我们为这个Hello World项目定义artifactId为hello-world。

    version制定了项目当前版本------1.0SNAPSHOT。SNAPSHOT意为快照,说明该项目还处于开发中,是不稳定版本。

    最后一个name元素声明了一个对于用户更为友好的项目名称,虽然这不是必须的。

2.编写主代码

    默认情况下,Maven假设项目主代码位于src/main/java目录,于是我们在hello-world文件夹下创建文件com/juvenxu/mvnbook/helloworld/HelloWorld.java,其内容如下:

package com.juvenxu.mvnbook.helloworld;

public class HelloWorld{
	public String sayHello(){
		return "Hello Maven";
	}
	public static void main(String [] args){
		System.out.println(new HelloWorld().sayHello());
	}
}

    代码编写完毕后,使用Maven进行编译,在hello-world文件夹下运行命令mvn clean compile。经过Maven编译,所有输出都在targer目录中。

3.编写测试代码

    Maven项目中默认的主代码目录是src/main/java,对应的,Maven项目中默认的测试代码目录是src/test/java。因此需要创建该目录。

    在编写测试代码之前,首先需要为Hello World项目添加一个JUnit依赖,修改项目的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.juvenxu.mvnbook</groupId>
  <artifactId>hello-world</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>Maven Hello World Project</name>
  <dependencies>
  <dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.7</version>
	<scope>test</scope>
  </dependency>
  </dependencies>
  </project>

    代码中添加了dependencies元素,该元素下可以包含多个dependency元素以声明项目的依赖,这里添加了一个junit依赖。有了这段声明,Maven就能自动从中央仓库下载junit-4.7.jar。scope为依赖范围,值为test表明该依赖只对测试有效。也就是说,在测试代码中使用import junit代码没有问题,如果在主代码中使用import junit代码,则会造成编译错误。如果不声明依赖范围,默认为compile,表示该依赖对主代码和测试代码都有效。

    配置了测试依赖,下面在src/test/java目录下创建测试类:

package com.juvenxu.mvnbook.helloworld;

import static org.junit.Assert.assertEquals;
import org.junit.Test;

public class HelloWorldTest{
	@Test
	public void testSayHello(){
		HelloWorld helloWorld = new HelloWorld();
		String result = helloWorld.sayHello();
		assertEquals("Hello Maven", result);
	}
}

    编写完代码,使用mvn clean test命令执行测试,检查其返回值是否正确。

4.打包

    在编译、测试之后,下一个重要步骤就是打包(package)。Hello World的pom中没有指定打包类型,默认的打包类型为jar。执行命令mvn clean package进行打包,在项目的target目录中将会生成一个名为hello-world-1.0-SNAPSHOT.jar的文件。至此,可以复制这个jar文件到其它项目的classpath中从而使用HelloWorld类。


5.依赖范围

上面提到,JUnit依赖的范围是test,实际上,Maven在编译项目主代码的时候使用一套classpath,在执行测试的时候会使用另一套classpath。依赖范围就是用来控制依赖与三种classpath(编译classpath、测试classpath、运行classpath)的关系,Maven有以下几种依赖范围:
    ①compile:编译依赖范围,如果没有指定,将默认使用该依赖范围,它对于编译、测试、运行三种classpath都有效。
    ②test:测试依赖范围,只对于测试classpath有效,在编译主代码或者运行项目时将无法使用此类依赖。
    ③provided:已提供依赖范围,对于编译和测试classpath有效,但在运行时无效。
    ④runtime:运行时依赖范围,对于测试和运行classpath有效,但编译时无效。
    ⑤system:系统依赖范围,对于编译和测试classpath有效,但在运行时无效。

下表表示了各种依赖范围与三种classpath的关系:

作用域编译时有效测试时有效运行时有效实例
compilespring-core.jar
test  junit.jar
runtime mysql-connector-java.jar
provided servlet-api.jar
system JDK的rt.jar


6.传递依赖

如果A依赖于B,B依赖于C,那么说A对B是第一直接依赖,B对C是第二直接依赖,A对于C是传递性依赖。现在假设有如下两种依赖关系:
    A -> B ->C -> X   (X版本是1.0)
    A -> D -> X          (X版本是2.0)
    X是A的传递性依赖,但是两条依赖路径上有两个版本的X,哪么哪个X会被Maven解析使用呢?两个版本都解析显然是不对的,因为那会造成依赖重复,因此必须选一个。Maven依赖调节的第一原则是:路径最近者优先。该例中X(1.0)的路径长度为3,而X(2.0)的路径长度为2,因此X(2.0)会被解析使用。
    但遇到路径长度相同时,在Maven2.0.8及之前版本中,是不确定解析哪个依赖。在Maven2.0.9开始,为了避免构建的不确定性,Maven定义了依赖调节的第二原则:第一声明者优先,在依赖路径相等的前提下,在pom中依赖声明的顺序决定了谁会被解析使用,即顺序最靠前的那个依赖将会被解析使用。

    简而言之:先看路径长短,优先依赖路径短的;如果路径长度相同,优先依赖先声明的。

    依赖传递不会传递scope为test的包,传递compile依赖范围的包。

    如果产生包冲突,可以使用<exclusions>标签排除依赖。


7.聚合

    当一个项目中有多个模块(module)的时候,如果分别对每个模块都进行编译,会显得十分麻烦,此时需要使用maven的聚合,将多个模块聚合在一起管理:



8.依赖继承

    当一个项目有多个模块时,我们可以把各模块所依赖的包统统放在父模块中管理,包括依赖的包名、版本号,而在子模块中则不需要再写版本号了。子模块继承父模块时,需要添加以下内容:

<parent>
		<groupId>org.konghao.cms</groupId>
		<artifactId>cms-parent</artifactId>
		<version>0.0.1-SNAPSHOT</version>
		<relativePath>../cms-parent/pom.xml</relativePath>
	</parent>

    在父模块中添加依赖的时候,需要这样使用标签:

<dependencyManagement>
<dependencies>
<dependency>

    而在子模块中,没有<dependencyManagement>标签。dependencyManagement能够让子模块继承父模块的依赖管理。


    父模块中,<packaging>属性的值为pom,子模块不为pom,应该为jar或war。通常我们会将继承和聚合都写在父模块中。

    注意:继承一定是pom文件路径,而聚合则是模块的路径。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值