JavaJava面试篇

maven实战

2017-12-28  本文已影响228人  坚持到底v2

总结

1. 国内的maven镜像站!!

在~/.m2目录下的settings.xml文件中增加

<mirrors>
<mirror>  
  <id>alimaven</id>  
  <name>aliyun maven</name>  
  <url>http://maven.aliyun.com/nexus/content/groups/public/</url>  
  <mirrorOf>central</mirrorOf>          
</mirror>
</mirrors>

2. pom 中使用 system 依赖需要注意

例如依赖了 ${project.basedir}/lib 目录下的 jar 包

        <dependency>
            <groupId>com.dingtalk.open</groupId>
            <artifactId>client-sdk.api</artifactId>
            <version>1.0.2</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/lib/client-sdk.api-1.0.2.jar</systemPath>
        </dependency>

打包时, system 依赖的 jar 包默认不会打到 target 中, 所以需要 maven-dependency-plugin

<build>
   <pluginManagement>
    <plugins>
        <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
        <plugin>
            <groupId>org.eclipse.m2e</groupId>
            <artifactId>lifecycle-mapping</artifactId>
            <version>1.0.0</version>
            <configuration>
                <lifecycleMappingMetadata>
                    <pluginExecutions>
                        <pluginExecution>
                            <pluginExecutionFilter>
                                <groupId>
                                    org.apache.maven.plugins
                                </groupId>
                                <artifactId>
                                    maven-dependency-plugin
                                </artifactId>
                                <versionRange>
                                    [2.10,)
                                </versionRange>
                                <goals>
                                    <goal>
                                        copy-dependencies
                                    </goal>
                                </goals>
                            </pluginExecutionFilter>
                            <action>
                                <ignore></ignore>
                            </action>
                        </pluginExecution>
                    </pluginExecutions>
                </lifecycleMappingMetadata>
            </configuration>
        </plugin>
    </plugins>
   </pluginManagement>

   <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>
               </configuration>
           </execution>
       </executions>
   </plugin>
</build>

也可以使用 maven-war-plugin

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.3</version>
    <configuration>
        <warName>${project.artifactId}</warName>
        <webResources>
            <resource>
                <directory>lib/</directory>
                <targetPath>WEB-INF/lib</targetPath>
                <includes>
                    <include>**/*.jar</include>
                </includes>
            </resource>
        </webResources>                    
    </configuration>
</plugin>

一、安装Maven:

1. 在windows上安装Maven:

检查JDK安装

要求: jdk1.4及以上版本

echo %JAVA_HOME%; 
java -version;

下载Maven

http://maven.apache.org/download.html
下载bin.zip,解压,

设置环境变量

增加 M2_HOME
Path增加%M2_HOME%\bin

验证

mvn -v 

2. Unix上安装Maven:

检查JDK安装

要求: jdk1.4及以上版本

echo %JAVA_HOME%; 
java -version;

下载 & 设置环境变量

mvnDirName="apache-maven-3.5.0"
mvnTarName="${mvnDirName}-bin.tar.gz"
wget http://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.5.0/binaries/${mvnTarName}
tar xf ${mvnTarName}
# 做一个软链接,以后升级只需要更新软链接的目标即可
ln -s ${mvnDirName} apache-maven
echo "export M2_HOME=`pwd`/apache-maven" >> /etc/bashrc
echo "export PATH=\"\$PATH:`pwd`/apache-maven/bin\"" >> /etc/bashrc

验证

mvn -v 

3. 安装目录分析

4. 设置HTTP代理

修改settings.xml,添加proxies元素:可以声明多个proxy,第一个被激活的proxy会生效

  <settings>
  ...
  <proxies>
    <proxy>
      <id>my-proxy</id>
      <active>true</active>
      <protocol>http</protocol>
      <host>1.1.1.1</host>
      <port>2222</port>
      <!--
      <username>***</username>
      <password>***</password>
      <nonProxyHosts>repository.mycom.com|*.google.com</nonProxyHosts>
      -->
    </proxy>
  </proxies>
  ...
  </settings>

5. Maven安装最佳实践:

5.1 设置MAVEN_OPTS环境变量:

mvn实际执行的是java命令,所以可以设置环境变量 MAVEN_OPTS,一般设置成 -Xms128m -Xmx512m ,因为Java的默认的最大可用内存往往不能够满足Maven运行的需要
尽量不要修改 mvn.bat或mvn 这两个执行脚本文件 因为升级时麻烦,且容易忘记
应该尽可能不修改安装目录下的文件

5.2 配置用户范围的 settings.xml

将 $M2_HOME/conf/settings.xml 复制到~/.m2/目录下修改

mkdir ~/.m2;
cp $M2_HOME/conf/settings.xml ~/.m2/ 

一个是全局的,一个是用户级的,还有就是不担心升级带来的配置更改

5.3 不要使用IDE内嵌的Maven:

在Eclipse的m2eclipse环境中,选择菜单
Windows=》Preferences=》Maven=》Installlation
添加一个外部Maven安装路径,并选中


三、maven使用入门

1. 编写POM

需要注意的是maven的Compiler插件默认只支持编译Java1.3,
因此需要配置该插件使其支持Java5.
如下所示:

  <build>
    <finalName>webfilemanage</finalName>
    <plugins>  
         <plugin>  
                <groupId>org.apache.maven.plugins</groupId>  
                <artifactId>maven-compiler-plugin</artifactId>  
                <configuration>  
                    <source>1.7</source>  
                    <target>1.7</target>  
                </configuration>  
         </plugin>  
    </plugins>
  </build>

2. 打包和运行:

默认打包生成的jar包是不能直接运行的,
带有main方法的类信息不会添加到manifest中(jar文件中的META-INF/MANIFEST.MF文件中没有Main-Class一行)
要想可以运行,需要借助maven-shade-plugin
配置文件

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>1.4</version>
    <executions>
      <execution>
        <phase>package</phase>
        <goals>
          <goal>shade</goal>
        </goals>
        <configuration>
          <transformers>
            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
              <mainClass>com.juvenxu.mavenbook.HelloWorldCli</mainClass>
            </transformer>
          </transformers>
        </configuration>
      </execution>
    </executions>
  </plugin>

或者使用 maven-jar-plugin 插件增加 manifestEntries
(除了可以增加Main-Class之外,还可以增加其他任意的想加的内容,例如Premain-Class、Can-Redefine-Classes等)

<plugin>  
    <groupId>org.apache.maven.plugins</groupId>  
    <artifactId>maven-jar-plugin</artifactId>  
    <version>3.0.2</version>  
    <configuration>  
        <archive>  
            <manifest>  
                <addClasspath>true</addClasspath>  
            </manifest>  
            <manifestEntries>  
                <Main-Class>  
                    com.xxx.test.App  
                </Main-Class>  
            </manifestEntries>  
        </archive>  
    </configuration>  
</plugin>  

2.1 生成源码包

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-source-plugin</artifactId>
    <version>2.1.2</version>
    <executions>
      <execution>
        <id>attach-sources</id>
        <phase>verify</phase>
        <goals>
          <goal>jar-no-fork</goal>
        </goals>
      </execution>
    </executions>
   </plugin>

2.2 生成java-doc包

  <plugin>          
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-javadoc-plugin</artifactId>
    <version>2.7</version>
    <executions>
      <execution>
        <id>attach-javadocs</id>
          <goals>
            <goal>jar</goal>
          </goals>
      </execution>
    </executions>
  </plugin> 

3. 使用archetype生成项目骨架:

mvn archetype:generate  

四、坐标和依赖:

1. 坐标详解:

一般构件名称为 artifactId-version[-classifier].packaging

2. 依赖的配置:

2.1 依赖的类型 type

对应于坐标中的packaging,默认是jar

2.2 依赖的范围 scope

首先需要知道maven在编译项目主代码的时候、在编译和执行测试的时候、和项目实际运行的时候
会分别使用3套classpath
而依赖的范围有

2.3 标记依赖是否可选optional

意思就是假设A依赖与B,B依赖于X和Y(可选依赖),
那么A不会有对X和Y的传递性依赖,A必须主动声明对X或Y的依赖

但是 应该避免使用可选依赖
应该把B分成B1和B2,分别对X和Y依赖

2.4 排除传递性依赖exclusions

内含多个<exclusion>元素,exclusion元素内指定groupId、artifactId、(不需要再指定version)表示排除的传递性依赖
然后再自己声明对某个构件的依赖,以使用自己的特定版本

2.5 导入依赖范围 import

一般此时type为pom,表示导入预定义好的依赖管理文件的内容
该依赖范围不会对三种classpath产生实际的影响

3. 传递性依赖:

假设A依赖B,B依赖C

4. 依赖调解:

假设A->B->C->X(1.0)、A->D->X(2.0)

5. 最佳实践:

5.1 排除依赖:

5.2 归类依赖:

例子:

    <properties>
     <springframework.version>2.5.6</springframework.version>
    </properties>

然后使用${}引用 相当于Java中的定义常量

    <version>${springframework.version}</version>

5.3 查看当前项目的已解析依赖:

mvn dependency:list

查看依赖树:

mvn dependency:tree

分析项目依赖:

mvn dependency:analyze 

结果中的WARNING有两个:

五、仓库

1. 仓库的分类:

本地仓库和远程仓库
远程仓库又包括中央仓库、私服、其他公共库

(1) 本地仓库

本地仓库在~/.m2/reposity/
可以通过修改settings文件:

<localRepository>D:\mavenrepo\</localRepository>

执行下面的命令 会将生成的jar包安装到本地仓库

mvn clean install

(2) 中央仓库:

在 $M2_HONE/lib/maven-x.y.z-uber.jar 中的 org/apache/maven/model/pom-4.0.0.xml 中
有一个超级POM文件,其中定义了中央仓库的位置,
其中<snapshots>属性是false,表示不从中央仓库下载快照版本

(3) 私服:

即使是个人机器也应该建立私服,好处多多:
加速构建、
节省带宽、
部署第三方构件、
降低中央仓库的负荷

(4) 远程仓库的配置:

在项目的pom文件里声明

    <repositories>
      <repository>
        <id>xx</id>
        <name>xx</name>
        <url>xx</url>
        <releases>true|false</release>
        <enabled>true | false </release>
        <updatePolicy>daily| never | always | interval:X分钟 </updatePolicy>
        <checksumPolicy>ignore | warn | fail </checksumPolicy>
        <snapshots>true|false</release>
      </repository>
    </repositories>

(5) 远程仓库的认证:

认证信息必须在settings.xml中,

    <servers>
      <server>
        <id>my-proj</id>
        <username>repo-user</username>
        <password>repo-pwd</password>
      </server>
    </servers>

2. 部署到远程仓库

需要配置pom.xml文件,配置 distributionManagement 元素,
如果需要认证,同上面一样

   <distributionManagement>
     <repository>
        <id>xx</id>
        <name>xx</name>
        <url>xx</url>
     </repository>
     <snapshotRepository>
        <id>xx</id>
        <name>xx</name>
        <url>xx</url>
     </snapshotRepository>
   </distributionManagement>

3. 快照版本:

强制让mvn检查更新

mvn clean install -U 

例如 2.1-SNAPSHOT,在每次发布的时候Maven会自动为构件打上时间戳,也就是将SNAPSHOT替换成20091214.221414-13这样的时间戳,表示2009年12月14号22点14分14秒的第13次快照

4. 从仓库解析依赖的机制:


不推荐在依赖声明中使用LATEST和RELEASE,
尤其是LATEST,今天可能是1.3版本,明天可能就是1.4-SNAPSHOT,非常不可靠,
RELEASE还相对可靠,
Maven3以后不再支持使用LATEST和RELEASE,
如果不设置插件版本,则相当于RELEASE,
Maven只会解析最新的发布版本构件
不过即使这样,还是有潜在的风险

5. 镜像:

在settings.xml中配置:

  <mirrors>
    <mirror>
      <id>xx</id>
      <url>xx</url>
      <mirrorOf>xx</mirrorOf>
    </mirror>
  </mirrors>

镜像仓库会屏蔽被镜像仓库,因此要保证镜像仓库的稳定性

6. 仓库搜索服务:

http://mvnrepository.com/

六、生命周期和插件

1. 何为生命周期?

Maven的生命周期是抽象的,实际工作由插件完成
每个构件步骤都可以绑定一个或多个插件行为,而且Maven为大多数构建步骤编写并绑定了默认插件
例如
maven-compiler-plugin负责编译,
maven-surfire-plugin负责测试

用户可以配置插件定制构建行为,
甚至自己编写插件

2. 三套生命周期:

每个生命周期都有一些阶段(phase),这些阶段是有顺序的,并且后面的phase依赖于前面的phase
而三套生命周期本身是相互独立的,用户可以只调用clean生命周期的某个阶段,而不会对其他生命周期产生影响

(1) clean生命周期

clean生命周期包含 pre-clean 、 clean 、 post-clean 三个阶段

(2) default生命周期

default生命周期包含 validate 、 initialize 、 generate-sources 、 process-sources(处理项目主资源文件,一般来说是对src/main/resources目录的内容进行变量替换等工作后,复制到项目输出的主classpath目录中)、 generate-resources 、 process-resources 、 compile 、 process-classes 、 generate-test-sources 、 process-test-sources 、 generate-test-resources 、 process-test-resources 、 test-compile 、 process-test-classes 、 test 、 prepare-package 、 package 、 pre-integration-test 、 integration-test 、 post-integration-test 、 verify 、 install 、 deploy

(3) site生命周期

site生命周期: pre-site 、 site 、 post-site 、 site-deploy

3. 命令行与生命周期:

4. 插件目标:

对于插件本身,为了能够复用代码,它往往可以完成多个任务
例如 maven-dependency-plugin,他能够基于项目依赖做很多事情
每个功能就是一个目标
maven-dependency-plugin 有10多个目标,
例如 dependency:analyze 、 dependency:tree等,
这是一种通用写法,前面是插件,冒号后面是目标

5. 插件绑定:

内置绑定,例如
maven-clean-plugin:clean 目标绑定了 clean 阶段,
maven-site-plugin:site 目标绑定了 site 阶段,
maven-site-plugin:deploy目标绑定了 site-deploy 阶段

还有很多生命周期的阶段没有绑定任何插件,因此也没有任何实际行为

(1) 自定义绑定:

    <build>
      <plugins>
        <plugin>
         <groupId><artifactId><version>
         <executions>
          <execution>
           <id>task name</id>
           <phase>verify</verify>
           <goals>
            <goal>jar-no-fork</goal>
           </goals>
           <configuration>
            <echo>...</echo>
           </configuration>
          </execution>
         </executions>
         <configuration>
          <source>xxx</source>
         </configuration>
        <plugin>
    </plugins>

有时候,即使不通过phase指定生命周期阶段,插件目标也能绑定到生命周期中去,
通过下面的命令查看插件详细信息,可以看到插件的目标默认被绑定到的生命周期阶段.

mvn help:describe -Dplugin=org.apache.plugins:maven-source-plugin:2.1.1 -Ddetail

也就是说,当用户配置使用maven-source-plugin插件的jar-no-fork目标的时候,
如果不知道phase参数,则默认绑定到package阶段

多个插件被绑定到同一个生命周期阶段时按照声明的先后顺序执行

6. 插件配置:

(1) 命令行插件配置

使用 -D 参数,
例如 mvn install -Dmvn.test.skip=true 表示跳过测试代码的编译,
因为 maven-surfire-plugin 会判断 mvn-test-skip 参数,其值为 true 则跳过测试
( -DskipTests 是跳过测试)

(2) 全局插件配置

在POM中,在plugin中配置 <configuration> 的子元素

(3) POM中插件任务配置

见上面的配置文件

7. 获取插件信息:

(1) 在线插件信息

通过apache或其他网站查看插件文档等

(2) 使用命令

mvn help:describe -Dplugin=groupId:artifactId:version -Ddetail 

可以简化成

mvn help:describe -Dplugin=compiler -Dgoal=compile -Ddetail

8. 从命令行调用插件:

mvn [options] [<goals>] [<phases>] -Dproperty=val 

从mvn的语法可以看到,
通过mvn命令可以激活生命周期阶段
还支持从命令行调用插件目标,因为有些任务不适合绑定在生命周期上,例help:describe、dependency:tree
那么为什么help能表示maven-help-plugin?

9. 插件解析机制:

(1) 插件仓库:

在POM中 使用pluginRepositories和pluginRepository声明插件仓库

(2) 插件默认的groupId:

org.apache.maven.plugins

(3) 插件的版本:

首先内置的超级POM中为所有核心插件设置了版本,
如果不是核心插件,maven则检查所有仓库中的可用版本,
然后做出选择,为了减少潜在的风险,
建议一定要写明版本

(4) 解析插件前缀:

通过解析仓库元数据,groupId/maven-metadata.xml,
默认只检查org.apache.maven.plugins和org.codehaus.mojo两个groupId的元数据,
可以在settings里加入自己的pluginGroups=>pluginGroup让maven检查你的仓库元数据,
然后在元数据xml文件中设置artifactId的prefix,
然后就可以用prefix来代表artifactId
然后通过上面介绍的解析插件版本的方法解析到插件版本,就得到了完整的插件坐标

七、聚合与继承:

1. 聚合:

聚合的POM文件其packaging类型为pom,同时设置

<modules>
  <module>xxx</module>
   ...
</modules>

module声明的是项目所在的文件夹路径及名称,所以聚合模块与其他模块的目录结构不一定是父子关系,
例如module可以设置成../xxx,那么它们就是平行关系

2. 继承:

  <parent>
    <groupId>chinaunicom.softwareri</groupId>
    <artifactId>unifiedaccess</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <relativePath>../xx/xx</relativePath> <!-- 设置相对路径 -->
  </parent>

可继承的POM元素有:groupId、version、description、organization、inceptionYear、url、developers、contributors、dsitributionMnagement、issueManagement、ciManagement、scm、mailingLists、properties、dependencyManagement、repositories、build、reporting

3. 依赖管理:

通过parent声明依赖管理来继承依赖是不合适的,因为不可能所有的模块都有相同的依赖

Maven提供的dependencyMangement元素既能让子模块继承父模块的依赖配置,又能保证子模块依赖的灵活性
使用dependencyManagement声明的依赖不会引入实际的依赖
但是他能够约束dependencies下的依赖使用
例如在parent中声明了dependencyManagement中的各种dependencies,
然后在子模块中声明dependencies时就不需要写version和scope,
这些已经在parent中统一声明过了

在dependencyManagement中声明的dependencies的scope还可以设置成import,type一般是pom,表示导入预定义好的依赖管理文件的内容

3.1 插件管理:

相应地maven提供了dependencyManagement元素帮助管理依赖

3.2 聚合与继承的关系:

聚合模块知道有哪些被聚合的模块,而被聚合的模块不知道被谁聚合
继承模块知道父模块的存在,但父模块不知道被谁继承,
它们唯一的共同点就是聚合模块和父模块的packaging都必须是pom 所以人们一般把他们结合在一起使用

4. 反应堆:

模块间的依赖关系构成一个有向非循环图(DAG=directed acyclic graph),不允许出现循环,
所以如果A依赖B,B又依赖A,Maven就会报错

(1) 裁剪反应堆

有时候仅仅想构件某几个模块
Maven提供的命令行选项

八、创建私服(Nexus)

http://www.sonatype.org/nexus/

1. 下载bundle或war文件,

bundle自带Jetty容器,因此不需要Web容器就可以直接启动Nexus
一般需要注意的是端口冲突,Nexus默认使用8081端口,编辑文件conf/plexus.properties,找到属性application-port,改端口号然后重启Nexus即可

2. 默认用户

默认的Nexus是匿名访问的,但匿名访问只有一些最基本的权限,要全面学习和管理Nexus,必须使用管理员登陆
默认admin/admin123

3. Nexus的仓库和仓库组

3.1 Nexus内置的仓库:

Nexus界面左边导航栏的repositories链接单击,在右边会看到列表,包含了所有类型的仓库
仓库有4种类型:group(仓库组)、hosted(宿主)、proxy(代理)、virtual(虚拟)

仓库的格式为maven2或maven1.
此外,仓库还有一个policy(策略),表示该仓库为发布版本仓库还是快照版本仓库,最后两列的值为仓库的状态和路径

这里不涉及maven1格式的仓库,由于virtual类型的仓库也是为了服务maven1格式,因此也被省略

3.2 创建Nexus宿主仓库

Nexus界面左边导航栏的repositories链接单击,
在右边点add,选择hosted repository,
然后填入仓库id和名称 repository type表示仓库的类型
Provider用来确定该仓库的格式,一般来说,选择默认的maven2 repository

然后是policy,根据需要来配置该仓库是发布版构件仓库还是快照版构件仓库

3.3 创建Nexus代理仓库:

同上,选择proxy repository

(1) 创建仓库组:
最好将常用的仓库放在前面 , 以便尽快地访问到包含构件的仓库

3.4 配置maven从Nexus下载构件

<profiles>
    <profile>
        <id>
        <repositories>
             <repository>  </repository>
        </repositories>
    </profile>
</profiles>

和类似的

<pluginRepository> 

<activeProfiles>   

配置完后maven还会不时地访问中央仓库,这就需要配置mirror,匹配*

3.5 部署构件到Nexus

使用maven,设置pom的distributionManagement 需要认证则在settings中设置server

3.6 手动部署第三方构件到Nexus

首先选择一个3rd party宿主仓库,然后选择artifact Upload

4. Nexus的权限管理:

Nexus是基于权限做访问控制的,服务器的每一个资源都有相应的权限来控制
管理员必须以role角色的方式赋予权限
例如要访问Nexus界面,就必须拥有status(读)权限

4.1 为项目分配独立的仓库:

首先建一个项目专用的仓库,
然后点击左边的repository targets链接,看右边的All(maven2),它的匹配值为.*,说明它可以匹配仓库下的任何路径

然后点击左边的privileges,在右边页面点击add-》repository target privilege
然后创建包含上述权限的角色,
然后将这个角色分配给项目团队成员

5. Nexus调度任务:

页面左边有scheduled tasks链接,点击add,选择调度任务类型,并配置运行方式

九、使用maven进行测试:

1. 运行

mvn test

测试报告内容
会根据你在test中写的测试类的数量,简单的说明,
运行了几个测试类,各运行了几个测试,运行情况 还有一个汇总的运行情况说明

测试类中使用 @Before @Test @After @Ignore等来标注方法

2. maven本身并不是单元测试框架

他只是在构建执行到特定生命周期阶段的时候,通过插件(maven-surefire-plugin)来执行JUnit或TestNG的测试用例
默认情况下,surefire的test目标会自动执行/src/test/java/下的所有符合命名模式的测试类,模式包括:

用户也就不用再定义测试集合(TestSuite)来聚合测试用例(TestCase)
需要注意的是以Tests结尾的测试类是不会自动执行的
当然也可以自定义要运行测试类的模式

还支持更高级的TestNG测试集合xml文件

3. 跳过测试:

mvn package -DskipTests,

也可以在pom中设置plugin的configuration的skipTests属性为true来长时间跳过测试

还可以使用 -Dmaven.test.skip=true 来跳过测试代码的编译,就是连测试代码编译都省了!
它同时控制了maven-compiler-plugin和maven-surefire-plugin两个插件的行为
在pom中的configuration属性是skip
实际上是compiler的testCompile目标和surefire的test目标都提供了一个参数skip用来跳过测试编译和测试运行,而这个参数的命令行表达式为maven.test.skip

4. 动态指定要运行的测试用例:

例如项目代码中有一个失败的测试用例,开发人员就会想要再次运行这个测试以获得详细的错误报告,使用

test参数的值必须匹配一个或者多个类,例如mvn test -Dtest 会报错误,可以使用-DfailIfNoTests=false来禁止这个报错功能

但是在命令行上没有相应的参数来指定要跳过测试的类,只能通过POM中配置

5. 包含与排除测试用例:

由于历史原因,某些测试类都是以Tests结尾的,
这就需要在POM中增加自动运行的模式,
配置surefire的includes中的include子元素的值为**/*Tests.java,
第一个**是表示任意路径,
第二个*表示匹配0或多个任意字符

类似地,还可以配置excludes的exclude子元素来排除那些不进行测试的类

6. 测试报告:

6.1 基本测试报告:

默认情况下,surefire会在项目的target/surefire-reports命令下生成两种格式的错误报告:
简单文本格式和与JUnit兼容的XML格式

6.2 测试覆盖率报告:

Cobertura是一个开源测试覆盖率统计工具,maven通过cobertura-maven-plugin与之集成,
可以使用简单的命令为maven项目生成测试覆盖率报告
例如:

mvn cobertura:cobertura

然后打开项目命令target/site/cobertura/下的index.html文件,就能看到测试覆盖率报告

7. 运行TestNG测试:

NG=NextGeneration下一代,支持测试组的概念,可以使用 @Test(groups={"util","medium"}) 在方法级别上对测试进行归类,这一点JUnit是做不到的

更多的自行查阅TestNG站点

8. 重用测试代码:

mvn package 默认不会把测试代码打包
要想把测试包打上,就要配置maven-jar-plugin将测试类打包,

    <executions>
      <execution>
         <goals>
        <goal>test-jar</goal>
     </goals>
      </execution>
    </executions>

test-jar的默认绑定生命周期阶段是package,所以声明了之后在package时就会运行这个goals

然后别人要引用这个包就可以在pom中声明这个包的type为test-jar就可以使用了

十一、使用maven构建web应用:

(1) 使用jetty-maven-plugin进行测试:

(2) 使用Cargo自动化部署:

十二、版本管理

1. 版本号定义约定

主版本.次版本.增量版本-里程碑版本
例如1.3.4-beta-2

2. 主干、标签与分支

标签用来标识主干或分支的某个点的状态,以代表项目的某个稳定状态,这通常就是版本发布时的状态

假设项目1.1.0发布之后,开始进入1.2.0-snapshot阶段,
可此时用户报告1.1.0版本有重大bug需要修复,
我们不能在主干中修bug,因为主干有太多变化,
我们也不能停止1.2.0-snapshot的开发,

因此这时候可以基于1.1.0创建一个1.1.1-snapshot分支,在这里进行bug修复,
然后为用户发布一个1.1.1增量版本,同时打上标签

当然,还不能忘了把bug修复涉及的变更合并到1.2.0-snapshot的主干中,主干在开发一段时间后,发布1.2.0版本

3. 自动化发布

如果不熟悉的话,建议一步一步地操作一遍,以得到最直观的感受:
检查是否有未提交的代码、是否有快照依赖、更新快照版至发布版、执行maven构建以及为源代码打标签等

当熟悉了版本发布流程后,我们就会希望借助工具将这一流程自动化
maven release plugin就提供了这样的功能
它主要有3个目标,分别为:

要为项目发布版本,首先需要为其添加正确的版本控制系统信息,
这是因为maven release plugin需要知道版本控制系统的主干、标签等地址信息才能执行相关的操作
一般配置项目的SCM信息如下所示:

    <project>
      ...
      <scm>
        <connection>scm:svn:http://xxx/x/x</connection>
        <developerConnection>scm:svn:https://x/x/x</developerConnection>
        <url>http://x/x/x</url>
      </scm>
    </project>

还需要配置release plugin的tagBase配置熟悉

4. 自动化创建分支:

maven release plugin的branch目标

5. gpg签名:

GnuPG 是 PGP标准的一个免费实现
maven-gpg-plugin的sign目标在verify阶段执行
还有就是gpg签名只在发布版发布的时候运行,可以写一个profile

十三、灵活的构建

1. maven属性:

最简单的就是通过<properties>元素自定义属性
然后使用${}来引用
除了这种属性之外,还有:

(1) 内置属性:

例如
${basedir}表示项目根目录,即表示包含pom.xml的目录,
${version}表示项目版本=${project.version}

(2) POM属性

pom文件内对应元素的值
例如
${project.actifactId}就表示<project>下<artifactId>元素的值
${project.build.sourceDirectory}表示项目主源码目录,即/src/main/java ${project.build.testSourceDirectory}表示src/test/java
${project.build.directory}表示target
${project.outputDirectory}表示target/classes
${project.build.finalName}

它们中一些属性的默认值都是在超级POM中定义的

(3) Settings属性

引用settings.xml文件中的值
例如
${settings.localRepository} 表示指向用户本地仓库的地址

(4) Java系统属性

例如
${user.home}指向用户目录
可以使用mvn help:system来查看所有的java系统属性

(5) 环境变量属性

例如
${env.JAVA_HOME} 表示指代JAVA_HOME环境变量的值

2. 构建环境的差异:

定义profile,为资源文件开启过滤(也就是将资源文件中的属性替换,默认就不替换属性的),
还可以定义多个资源文件路径
通过 mvn clean install -PprofileId 来激活profile

示例

   <resources>  
      <resource>  
        <directory>src/main/resources</directory>  
        <filtering>true</filtering>  
        <includes>  
          <include>**/*.xml</include> 
        </includes> 
      </resource> 
      <resource> 
        <directory>src/main/resources</directory> 
        <filtering>false</filtering> 
        <excludes> 
          <exclude>**/*.xml</exclude>  
        </excludes>  
      </resource>  
      ...  
    </resources>  

3. maven profile:

4. 激活profile:

(1) 命令行激活

mvn clean install -PprofileId1,profileId2

(2) settings文件显式激活:

<activeProfiles>
    <activeProfile></activeProfile>
</activeProfiles>

(3) 系统属性激活:

设置profile的属性

<activation>
   <property>
       <name>xx</name>
       <value>xx</value> 
   </property>
</activation>

表示当某属性存在或某属性的值为xx的时候激活

(4) 操作系统环境激活:

<activation>
     <os>
         <name>Windows XP</name>
         <family>Windows</family>
         <arch>x86</arch>
         <version>5.1.2600</version>
     </os>
</activation>

这些属性的值可以查看环境中的系统属性os.name、os.arch等获得

(5) 文件存在与否激活

<activation><file><missing><exists>

(6) 默认激活:

<activation>
   <activeByDefault>true</activeByDefault>
</activation> 

需要注意的是,如果POM中有任何一个profile通过以上其他任意一种方式被激活了,所有的默认激活配置都会失效!

(7) 查看激活的profile和所有的profile:

mvn help:active-profiles 
mvn help:all-profiles

5. profile的种类

pom中的profile可以使用的元素非常多,
而settings中的因为不能随pom一起发布,
所以可使用的元素很少,包括repositories、pluginRepositories、properties

6. web资源过滤:

使用maven-war-plugin的configuration 的 <webResources>定义webresource资源文件

<webResources>
    <resource>
       <filtering>true</filtering>
       <directory>src/main/webapp</directory>
       <includes>
          <include>**/*.css</include>
          <include>**/*.js</include>
       </includes>
    </resource>
</webResources>

7. 使用profile激活集成测试:

一般单元测试执行时间短,而集成测试执行时间长,虽然我们应尽量执行所有的测试,但是当集成测试较多的时候高频率运行它们就变得不现实
所以,较高频率执行单元测试、较低频率执行集成测试是不错的选择

使用TestNG中的组的概念能很好的支持单元测试和集成测试的分类标记 @Test(groups={"unit"}) @Test(groups={"integration"})

然后在pom中配置surefire的configuration的<groups>unit</groups>,再写一个profile,指定groups为unit,integration.

然后在hudson中每隔15分钟检查一次更新,有更新则默认执行单元测试的构建,然后配置一个定时任务,每天执行2次,执行一个激活指定profile的构建

十四、生成项目站点:

将pom的信息用web的形式显示 maven-site-plugin

十五、m2eclipse:

十六、Archetype:maven-archetype-plugin插件

1. 使用:

mvn archetype:generate:

2. 批处理方式:

mvn archetype:generate -B -DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeAritifactId=maven-archetype-quickstart \
-DgroupId=... 

这个例子中Archetype的坐标为org.apache.maven.archetypes:maven-archetype-quickstart

3. 常用Archetype介绍:

maven中央仓库中有200多个Archetype 还有很多没有发布到中央仓库的 这里介绍几个常用的
(1) maven-archetype-quickstart:可能是最常用的
(2) maven-archetype-webapp:

上一篇 下一篇

猜你喜欢

热点阅读