Maven
Maven
<?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.0http://maven.apache.org/maven-v4_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和3来说,他只能是4.0.0。
groupId定义了项目属于哪个组,这个组往往会和项目所在的组织或公司存在关联。
artifactId定义了当前Maven项目在组中唯一的ID。
version指定了Hello World项目当前的版本。
name元素声明了一个对于用户更为友好的项目名称。
HTTP代理
<settings> <proxy> <id>my-proxy</id> <active>true</active> <protocol>http</protocol> <host>192.168.168.1</host> <port>3122</port> <!-- <username>username</username> <password>password</password> <nonProxyHosts>my.site.com|*.google.com</nonProxyHosts> --> </proxy> </settings>
编写主代码
在绝大多数情况下,应该把项目代码放到src/main/java目录下,而无需额外的配置,Maven会自动找到项目主代码。使用Maven进行编译,在项目根目录下运行命令mvn clean compile
编写测试代码
Maven项目中默认的测试代码目录是src/test/java。在编写测试用例之前应当先创建该目录。
<project> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.7</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>com.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> </build> </project>
代码中添加了dependencies元素,该元素下可以包含多个dependency元素以声明项目的依赖。
元素scope为依赖范围,若依赖范围为test则表示该依赖只对测试有效。
Maven的核心插件compiler插件默认只支持编译Java1.3,因此需要配置该插件使其支持1.5。
执行mvn clean test
打包和运行
将项目进行编译、测试之后,下一个重要步骤就是打包。默认打包类型为jar。执行命令mvn clean package打包。
默认打包生成的jar是不能够直接运行的,因为带有main方法的类信息不会添加到manifest中。为了生成可执行的jar文件,需要借助maven-shade-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.MainfestResourceTransformer"> <mainClass>com.juvenxu.mvnbook.helloworld.HelloWorld</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin>
使用Archetype生成项目骨架
mvn archetype:generate
Eclipse
maven-archetype-quickstart
坐标和依赖
坐标详解
<groupId>org.sonatype.nexus</groupId> <artifactId>nexus-indexer<artifactId> <version>2.0.0</version> <packaging>jar</packaging>
groupId 定义当前Maven项目隶属的实际项目。
artifactId 该元素定义实际项目中的一个Maven项目(模块),推荐的做法是使用实际项目名称作为artifactId的前缀。
version 该元素定义Maven项目当前所处的版本。
packaging 该元素定义Maven项目的打包方式。
classifier 该元素用来帮助定义构建输出的一些附属构件。
依赖的配置
<project> <dependencies> <dependency> <groupId>…</groupId> <artifactId>…</artifactId> <version>…</version> <type>…</type> <scope>…</scope> <optional>…</optional> <exclusions>…</exclusions> </dependency> </dependencies> <project>
groupId,artifactId,version 依赖的基本坐标
type依赖的类型
scope 依赖的范围
optional 标记依赖是否可选
exclusions 用来排除传递性依赖
依赖范围
依赖范围就是用来控制依赖与这三种classpath(编译、测试、运行)的关系,Maven有以下几种依赖范围
compile:编译依赖范围。如未指定就会默认使用该依赖范围。对于编译、测试、运行三种classpatch都有效。(spring-core)
test:测试依赖的范围。使用此依赖范围的Maven依赖,只对测试classpath有效,在编译主代码或者运行项目的使用时将无法使用。(JUnit)
provided:已提供依赖范围。使用此依赖的Maven依赖,对于编译和测试classpath有效,但在运行时无效。(servlet-api)
runtime:运行时依赖范围。使用此依赖范围的Maven依赖,对于测试和运行classpath有效,但在编译主代码时无效。(JDBC)
system:系统依赖范围。该依赖与三种classpath的关系,和provided依赖范围完全一致。但是,使用system范围的依赖时必须通过systemPath元素显式地指定依赖文件的路径。
<dependency> <groupId>javax.sql</groupId> <artifactId>jdbc-stdext</artifactId> <version>2.0</version> <scope>system</scope> <stystemPath>${java.home}/lib/rt.jar</systemPath> </dependency>
传递性依赖
account-email -> spring-core -> commons-logging
account-mail有一个compile范围的spring-core依赖,spring-core有一个compile范围的commons-logging依赖,那么commons-logging就会成为account-email的compile范围依赖,common-logging是account-email的一个传递性依赖。
传递性依赖和依赖范围
compile test provided runtime
_________________________________________________________________
compile compile ---- ---- runtime
_________________________________________________________________
test test ---- ---- test
_________________________________________________________________
privided privided ---- ---- privided
_________________________________________________________________
runtime runtime ---- ---- runtime
_________________________________________________________________
依赖调解
第一条原则:路径最近者优先。(X1的路径长度为3,而路径X2的长度为2,X2会被解析使用)
第二条原则:第一声明者优先。(在依赖路径长度相等的前提下,在POM中依赖声明中最靠前的依赖优胜)
可选依赖
<project> <modelVersion>4.0.0</modelVersion> <groupId>com.juvenxu.mvnbook</groupId> <artifactId>project-b</artifactId> <version>1.0.0</version> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.10</version> <optional>true</optional> </dependency> <dependency> <groupId>postgresql</groupId> <artifactId>postgresql</artifactId> <version>8.4-701.jdbc3</version> <optional>true</optional> </dependency> </dependencies> </project>
使用<optional>元素表示mysql-connector-java和postgresql这两个以来为可选依赖,他们只会对当前项目B产生影响,但其他项目依赖于B的时候,这两个依赖不会被传递。因此,当项目A依赖于项目B的时候,如果其实际使用基于MySql数据库,那个在项目A中就需要显示地声明mysql-connector-java这一依赖。
最佳实践
仓库
版本管理
1.3.4-beta-2
<主版本>.<次版本>.<增量版本>-<里程碑版本>
<project> <scm>
<connection>scm:svn:http://192.168.1.11/app/trunk</connection>
<developerConnection>scm:svn:https://192.168.1.11/app/trunk</developerConnection> <url>http://192.168.1.11/account/trunk</url> </scm> <project>
connection元素表示一个只读的scm地址
developerConnection元素表示可写的scm地址
url表示可以在浏览器中访问的scm地址
Maven Release Plugin
release:prepare 准备版本发布
release:rollback 回退release所执行的操作
release:perform 执行版本发布
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-release-plugin</actifactId> <version>2.0</version> <configuration> <tagBase>https://192.168.1.11/app/tags/</tagBase> <branchBase>https://192.168.181.11/app/branches/</branchBase> </configuration> </plugin>
使用如下命令,maven-release-plugin就会自动为所有子模块使用与父模块一致的发布版本和新的SPANSHOT版本
$mvn release:prepare –DautoVersionSubmodules=true;
自动化创建分支
$mvn release:branch –DbranchName=1.1.x –DupdateBranchVersions=true –DupdateWorkingCopyVersion=false
-DbranchName=1.1.x用来配置所要创建的分支的名称
-DupdateBranchVersions=true 表示为分支使用的新版本
-DupdateWorkingCopyVersions=false 表示不更新本地代码
Maven属性
通过<properties>元素用户可以自定义一个或多个Maven属性,然后在POM的其他地方使用${属性名称}的方式引用该属性。
内置属性
- ${basedir} 表示项目根目录(pom文件的目录)
- ${version} 标示项目版本
POM属性
- ${project.build.sourceDirectory} 项目的主源码目录(src/main/java/)
- ${project.build.testSourceDirectory} 项目的测试源码目录(src/test/java/)
- ${project.build.directory} 项目构建输出目(target/)
- ${project.outputDirectory} 项目主代码编译输出目录(target/classes)
- ${project.testOutputDir} 项目测试代码编译输出目录(target/testclasses)
- ${project.groupId} 项目的groupId
- ${project.artifactId} 项目的artifactId
- ${project.version} 项目的version(${version})
- ${project.build.finalName} 项目打包输出文件名称(${project.artifactId}-${project.version})
Settings属性
${settings.localRepository}
以settings.开头的属性引用settings.xml文件中XML元素的值。
Java系统属性
${user.home}
Java系统属性都可以使用Maven属性引用(mvn help:system)。
环境变量属性
${env.JAVA_HOME}
环境变量都可以使用以env.开头的Maven属性引用。
资源过滤
database.jdbc.driverClass = ${db.driver} database.jdbc.connectionURL = ${db.url} database.jdbc.username = ${db.username} database.jdbc.password = ${db.password}
数据库配置文件设置
<profiles> <profile> <id>main-db-config</id> <properties> <db.driver>mysql.jdbc.Driver</db.driver> <db.url>jdbc:mysql://localhost:3306/test<db.url> <db.username>root<db.username> <db.password>root-pwd<db.password> </properties> </profile> <profile> <id>test-db-config</id> <properties> <db.driver>mysql.jdbc.Driver</db.driver> <db.url>jdbc:mysql://192.168.1.11:3306/test<db.url> <db.username>test<db.username> <db.password>test-pwd<db.password> </properties> </profile> </profiles>
maven-resources-plugin默认只是将项目主资源文件复制到主代码编译输出目录中,测试资源文件复制到测试代码编译输出目录中。
为主资源目录开启过滤
<resources> <resource> <directory>${project.basedir}/src/main/resource</directory> <filtering>true</filtering> </resource> </resources>
为测试资源目录开启过滤
<testResources> <testResource> <directory>${project.basedir}/src/test/resource</directory> <filtering>true</filtering> </testResource> </testResources>
激活profile
1 命令行激活
用户可以使用mvn命令行参数-P加上profile的id来激活profile,多个id之间用逗号间隔。
$mvn clean install –Pdev–x,dev-y
2 settings文件显式激活
<settings> <activeProfiles> <activeProfile>dev-x</activeProfile> </activeProfiles> </settings>
某系统属性存在且值确定时激活profile
<profiles> <profile> <activation> <property> <name>test</name> <value>x</value> </property> </activation> </profile> </profiles>
命令行生命系统属性
$mvn clean install –Dtest=x
默认激活
<profiles> <profile> <activation> <activeByDefautl>true</activeByDefault> </activation> </profile> </profiles>
如果POM中有任何一个profile通过以上其他任意一种方式被激活了,所有的默认激活配置都会失效。
列出当前激活的profile
$mvn help:active-profiles
列出所有的profile
$mvn help:all-profile
POM中profile可使用的元素
<project> <repositories> <pluginRepositories> <distributionManagement> <dependencies> <dependencyManagement> <modules> <properties> <reporting> <build> <plugins> <defaultGoal></defaultGoal> <resources> <testResources> <finalName> </build> </project>
profile激活集成测试
TestNG中分组测试标记
@Test(groups = {“unit”}) @Test(groups = {“integration”})
在profile中配置执行TestNG测试组
<profiles> <profile> <id>full-test</id> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins<groupId> <artifactId>maven-surefire-plugin<artifactId> <version>2.5<version> <configuration> <groups>unit,integration</groups> </configuration> </plugin> </plugins> </build> </profile> </profiles>
默认Maven只会执行单元测试。如果想要执行集成测试,就需要激活full-test profile,在这个profile中配置了maven-surefire-plugin执行unit和integration两个测试组。