Maven学习笔记(十一):灵活的构建

典型的项目会有开发环境、测试环境和产品环境,这些环境的数据库配置不尽相同,那么项目构建的时候就需要能够识别所在的环境并使用正确的配置。还有一种情形是,项目开发了大量的集成测试,这些测试运行起来非常耗时,不适合在每次构建项目的时候都运行,因此需要一种手段能让我们在特定的时候才激活这些集成测试。Maven为了支持构建的灵活性,内置了三大特性,即属性、Profile和资源过滤。本章将介绍这些特性。

Maven属性

Maven的六类属性:

Maven一共有六类属性,分别是:

1.  内置属性:主要有两个常用内置属性-${basedir}表示项目根目录,即包含pom.xml文件的目录;${version}表示项目的版本。

2.  POM属性:用户可以使用该类属性引用POM文件中对应元素的值。例如${project.artifactId}就对应了<project><artifactId>元素的值,常用的POM属性包括:

    • ${project.build.sourceDirectory}:项目的主源码目录,默认为src/main/java/。
    • ${project.build.testSourceDirectory}:项目的测试源码目录,默认为src/test/java/。
    • ${project.build.directory}:项目构建输出目录,默认为target/。
    • ${project.outputDirectory}:项目的主代码编译输出目录,默认为target/classes/。
    • ${project.testOutputDirectory}:项目测试代码编译输出目录,默认为target/test-classes/。
    • ${project.groupId}:项目的groupId。
    • ${project.artifactId}:项目的artifactId。
    • ${project.version}:项目的version。
    • ${project.build.finalName}:项目打包输出文件的名称,默认为${project.artifactId}-${project.version}。

这些属性都对应了一个POM元素,它们中的一些属性的默认值是在超级POM中定义的。

3.  自定义属性:用户可以在POM的<properties>元素下自定义Maven属性。例如:

<project>
    ...
     <properties>
          <my.prop>hello</my.prop>
     </properties>
     ...
</project>     

然后在POM中其他地方使用${my.prop}的时候会被替换成hello。

4. Settings属性:与POM属性同理,用户使用以settings.开头的属性引用settings.xml文件中XML元素的值,如常用的${settings.localRepository}指向用户本地仓库的地址。

5. Java系统属性:所有Java系统属性都可以使用Maven属性引用,例如${user.home}指向了用户目录。用户可以使用mvn help:system查看所有的Java系统属性。

6. 环境变量属性:所有环境变量都可以使用以env.开头的Maven属性引用。例如${env.JAVA_HOME}指代了JAVA_HOME环境变量的值。用户可以使用mvn help:system查看所有的Java系统属性。

使用范例:

在一个多模块项目中,模块之间的依赖比较常见,这些模块通常会使用同样的groupId和version,这个时候就可以使用POM属性。

<dependencies>
     <dependency>
          <groupId>${project.groupId}</groupId>
          <artifactId>account-email</artifacId>
          <version>${project.version}</version>
     </denpendency>
     <dependency>
          <groupId>${project.groupId}</groupId>
          <artifactId>account-persist</artifacId>
          <version>${project.version}</version>
     </denpendency>
</dependencies>

通常,甚至该子模块的groupId和version也在聚合模块中约定好,那么现在这几个模块的groupId和version就做到了完全的一致。

构建环境的差异:

在不同的环境中,项目的源码应该使用不同的方式进行构建。例如,我们在开发环境可能使用一套数据库配置,在线上环境可能使用另外一套数据库配置,相似的,对于缓存的配置、对于其他应用的RFC链接都可能在不同的生产环境下有不同的配置。

资源过滤:

为了应对环境的变化,我们需要将会发生变化的部分提取出来。例如对于数据库的配置来说,我们一般会在src/main/resources目录下添加数据库的配置文件.properties文件。连接数据库使用的驱动类、URL、用户名和密码都可能发生变化,因此用Maven属性取代它们:

database.jdbc.driverClass=${db.driver}

database.jdbc.connectionURL=${db.url}

database.jdbc.username=${db.username}

database.jdbc.password=${db.password}

既然使用了Maven属性,我们就需要定义他们,在这里我们需要用到profile将其包裹起来,针对项目的不同配置,我们应该把profile定义在POM中。

<profiles>
     <profile>
          <id>dev</id>
          <properties>
               <db.driver>com.mysql.jdbc.Driver</db.driver>
               <db.url>jdbc:mysql://192.168.1.100:3306/test</db.url>
               <db.username>dev</db.username>
               <db.password>dew-pwd</db.password>
          </properties>
     </profile>
</profiles>    

这里将这个profile命名为dev是为了将开发环境下的配置与其他环境区别开来。

在默认情况下,Maven属性只会在POM中被解析,现在我们需要的是其在资源文件中也要被解析,因此我们需要定制maven-resources-plugin的行为,使其在处理资源文件时,能够对Maven属性进行过滤,即开启资源过滤。

为主资源目录开启过滤:

<resources>
     <resource>
          <directory>${project.basedir}/src/main/resources</directory>
          <filtering>true</filtering>
     </resource>
</resouces>

为测试资源开启过滤:

<testResources>
     <testResource>
          <directory>${project.basedir}/src/test/resources</directory>
          <filtering>true</filtering>
     </testResource>
</testResouces>

主资源目录和测试资源目录都可以超过一个,Maven允许用户声明多个资源目录,并且为每个资源目录提供不同的过滤配置。

<resources>
     <resource>
          <directory>${project.basedir}/src/main/resources</directory>
          <filtering>true</filtering>
     </resource>
     <resource>
          <directory>/src/main/sql</directory>
          <filtering>false</filtering>
     </resource>
</resouces>

最后我们只需要在使用mvn的时候,在命令行激活profile,Maven就能够在构建项目的时候使用profile中属性值替换数据库配置文件中的属性引用,命令如下:

     $mvn clean install -Pdev

mvn的- P参数表示在命令行激活一个profile。这里激活了id为dev profile。可以在处理完之后的资源文件中看到,所有maven属性都已经被替换了过来。

Maven profile:

在不同环境下的构建很可能是不同的,典型的情况就是数据库的配置。除此之外,有些环境可能需要配置插件执行一些特殊的操作,或者使用特殊版本的依赖,或者需要一个特殊的构件名称。为了能让构建在各个环境下方便地移植,Maven引入了profile的概念。profile能够在构建的时候修改POM的一个子集,或者添加额外的配置元素。用户可以使用很多方式激活profile,以实现构建在不同环境下的移植。

激活profile: 

1 .命令行激活

用户可以使用mvn命令行参数-P加上profile的id来激活profile,多个id之间以逗号分隔。例如,下面的命令激活了dev-x和dev-y两个profile:

$mvn clean install -Pdev-x, dev-y

2.settings文件显式激活

如果用户希望某个profile默认一直处于激活状态,就可以配置settings.xml文件的activeProfiles元素,表示其配置的profile对于所有项目都处于激活状态,代码如下:

<settings>
     ...
     <activeProfiles>
          <activeProfile>dev-x</activeProfile>
     </activeProfiles>
</settings>

3 .系统属性激活

4. 操作系统环境激活

5. 文件存在是否激活

6. 默认激活

最下面的4种方式并不常用,因此不多做介绍。

Profile的种类:

根据具体的需要,可以在以下位置声明profile:

  • pom.xml:很显然,pom.xml中声明的profile只对当前项目有效。
  • 用户settings.xml:用户目录下.m2/settings.xml中的profile对本机上该用户所有的Maven项目有效。
  • 全局settings.xml:Maven安装目录下conf/settings.xml中的profile对本机上所有的Maven项目有效。

为了不影响其他用户且方便升级Maven,用户应该选择配置用户范围的settings.xml,避免修改全局范围的settings.xml文件。也正是因为这个原因,一般不会在全局的settings.xml文件中添加profile。

不同类型的profile中可以声明的POM元素也是不同的,pom.xml中的profile能够随着pom.xml一起被提交到代码仓库中、被Maven安装到本地仓库中、被部署到远程Maven仓库中。换言之,可以保证该profile伴随着某个特定的pom.xml一起存在,因此它可以修改或者增加很多POM元素,见如下:

<project>
     <repositories></repositories>
     <pluginRepositories></pluginRepositories>
     <distributionManagement></distributionManagement>
     <dependencies></dependencies>
     <dependencyManagement></denpendencyManagement>
     <modules></modules>
     <properties></properties>
     <reporting></reporting>
     <build>
          <plugins></plugins>
          <defaultGoal></defaultGoal>
          <resources></resources>
          <testResources></testResources>
          <finalName></finalName>
     </build>
</project>

由于settings.xml与具体项目无关,所以在其中可以配置的profile元素较少:

<project>
     <repositories></repositories>
     <pluginRepositories></pluginRepositories>
     <properties></properties>
<project>
时间: 2024-10-12 20:41:25

Maven学习笔记(十一):灵活的构建的相关文章

Maven学习笔记之——仓库(中)

Maven学习笔记之--仓库(中) 1.    远程仓库的配置 当出现默认的中央仓库无法满足我们的需求或者连接不上的时候.我们可以通过POM文件来指定远程仓库. <repositories> <repository> <id>jboss-maven2-release-repository</id> <name>JBoss Repository</name> <url>http://repository.jboss.org/

Maven学习笔记之——仓库(上)

Maven学习笔记之--仓库(上) 1.    何为maven仓库 Maven可以在某一指定位置统一存放所有maven项目共享的构件.此指定位置就是maven仓库.实际的项目将不再自己存放其所依赖的构件.他们只需要声明这些依赖的坐标.在需要的时候就会自动根据坐标找到仓库中的构件.并使用他们. 仓库的意义:减少磁盘占用空间.去除大量重复的构件.尤其是项目越来越多.越来越大的时候.更便于统一管理所有控件. 2.    仓库的布局 任何一个构件都有其唯一的坐标.根据这个坐标可以定义其在仓库中的唯一存储

Maven学习笔记之——坐标和依赖(上)

Maven学习笔记之--坐标和依赖(上) 1.    Maven坐标概念 Maven通过构件的坐标来在Maven仓库中定位到具体的构件.Maven的坐标元素包括groupId.artifactId.versiion.packaging.classifier.Maven内置了一个中央仓库地址.需要时Maven会根据坐标到其中下载.具体关于中央仓库的介绍在后面. 2.    Maven坐标详解 比如下面一组坐标: <groupId>org.andy.items</groupId> &l

Maven学习笔记之——坐标和依赖(中)

Maven学习笔记之--坐标和依赖(中) 1.    传递性依赖 1.1    何为传递性依赖 项目中经常有引入一个jar包还要引入其他与其相关的jar包.自己搜的话要注意很多.比如版本问题等.而Maven会解析解析各个直接依赖的POM.将哪些必要的间接依赖以传递依赖的形式引入到项目中. 依赖范围不仅可以控制依赖与三种classpath关系.还对传递依赖产生影响. 假设A依赖B,B依赖C,我们说A对于B是第一直接依赖,B对于C是第二直接依赖,A对于C是传递性依赖.第一直接依赖的范围和第二直接依赖

Maven学习笔记之——坐标和依赖(下)

Maven学习笔记之--坐标和依赖(下) 1.    最佳实践 归纳Maven依赖使用的常用技巧.方便用来避免和处理很多常见问题. 1.1.     排除依赖 传递性依赖会给项目隐式地引入很多依赖,这极大地简化了项目依赖的管理.但是有些时候这种特性也会带来问题.例如,当前项目有一个第三方依赖,而这个第三方依赖由于某些原因依赖了另外一个类库的SNAPSHOT版本,那么这个SNAPSHOT就会成为当前项目的传递性依赖,而SNAPSHOT的不稳定性会直接影响到当前的项目.这时候需要排除掉该SNAPSH

Maven学习笔记(三):Maven的聚合和继承

Maven的聚合其实就是把各个项目拷贝到一个项目里,便于统一构建(这种是父子目录结构构件,个人喜欢这种,平行结构不喜欢),实现聚合的方式为: -- 新建一个普通的Maven项目,只保留pom文件,其他的目录结构都删除 -- 配置新建项目的pom文件: 1 <project ...> 2 <modelVersion>4.0.0</modelVersion> 3 <groupId>XXXX</groupId> 4 <artifactId>

Maven学习笔记之——三套生命周期

Maven学习笔记之--三套生命周期 Maven命令的输入往往就对应了生命周期.比如mvncompile就表示执行默认生命周期阶段compile.Maven的生命周期是抽象的.其实际行为都是由插件完成的.比如mvncompile就可能会由maven-compile-plugin完成.生命周期和插件是协同工作. 1.    何为生命周期 项目构件中进行的清理.编译.测试及部署都可以视作一个一个项目的生命周期.但是每个项目每个人都有不一样的顺序不一样的实现方式.没有统一性带来的不方便已经不言而喻.

Maven学习笔记(二):Maven仓库

Maven仓库的知识点比较少,理解起来也很简单. 仓库只有两类:本地仓库和远程仓库.所谓本地仓库就是自己机器上的仓库,在setting.xml文件中进行配置: 1 <localRepository>E:/MavenStore</localRepository> 本地仓库中存储的就是在使用Maven解析项目时从远程仓库下载的依赖和自己安装的一些构建. 远程仓库很明显就是网络上的仓库,存储在一个神秘的地方(好吧,其实我是不知道在哪里).当Maven解析项目时,如果本地没有需要的依赖,就

《Hibernate学习笔记十一》:树状结构设计

<Hibernate学习笔记十一>:树状结构设计 这是马士兵老师讲解Hibernate的一个作业题,树状结构设计,这是一个比较典型的例子,因此有必要写篇博文记录下. 树状结构的设计,它是在同一个类中使用了多对一(ManyToOne)和一对多(OneToMany). 在完成这个题目我们应该按照如下的步骤进行: 1.先思考数据库的模型应该是什么样的?? 数据库中的模型应该如下:即存在id p_id 2.思考面向对象的模型,及如何来进行映射??? 根据数据库中表的特点,对象应该有id name;由于