maven实战

作者: 坚持到底v2 | 来源:发表于2017-12-28 11:24 被阅读228次

    总结

    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. 安装目录分析

    • bin/ --运行脚本,还有m2.conf,这是classwords的配置文件
    • conf/ --有一个非常重要的文件settings.xml 不建议直接修改此文件,将此文件复制到~/.m2/目录下再修改 方便日后升级
    • boot/ --只有一个文件,plexus-classwords-x.x.x.jar,这是一个类加载器框架 不必关心此文件
    • lib/ --Maven运行时需要的类库

    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. 坐标详解:

    • groupId
    • artifactId
    • version
    • packaging(默认是jar)
    • classifier(可选)

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

    2. 依赖的配置:

    2.1 依赖的类型 type

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

    2.2 依赖的范围 scope

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

    • (1) compile(默认值.对于编译、测试、运行三种classpath都有效)

    • (2) test(只对测试classpath有效,编译和运行时不需要,典型例子是JUnit)

    • (3) provided(只对于编译和测试classpath有效,典型例子是servlet-api,运行时由于容器已经提供)

    • (4) runtime(对于编译无效、对于测试和运行有效,典型例子是JDBC驱动实现,项目主代码只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体的JDBC驱动)

    • (5) system(和provided一样,但是使用system范围的依赖必须通过systemPath元素显式地指定依赖文件的路径 由于此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此需要谨慎)

    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

    • 如果B对C的依赖是compile,那么A对C的传递性依赖和A对B的依赖一致

    • 如果B对C的依赖是test,那么A对C没有传递性依赖,这是很显然的,C只对测试B有用,对A当然没用

    • 如果B对C的依赖是provided,那么只有A对B的依赖也是provided的时候,A对C才有传递性依赖(也是provided)

    • 如果B对C的依赖是runtime,那么A对C的传递性依赖和A对B的依赖一致,除了A对B的依赖是compile的时候,此时A对C的传递性依赖是runtime

    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有两个:

    • used undeclared dependencies 表示使用了没有显式声明的依赖(例如使用了传递性依赖的包中的类),有潜在的风险,应该进行显式声明

    • unsed declared dependencies表示未使用但声明了的,不能简单的删除其声明 因为执行测试和运行时需要的依赖他不能分析,例如spring-core是运行spring framework项目必须有的类库,显然不应该删除

    五、仓库

    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>
    
    • 可以使用*,还可以使用 external:*表示匹配所有远程仓库

    • 还可以 *,!repo1表示匹配所有仓库,repo1除外

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

    6. 仓库搜索服务:

    http://mvnrepository.com/

    六、生命周期和插件

    1. 何为生命周期?

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

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

    2. 三套生命周期:

    • clean生命周期的目的是清理项目,

    • default生命周期的目的是构建项目,

    • site生命周期的目的是建立项目站点

    每个生命周期都有一些阶段(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. 命令行与生命周期:

    • (1) mvn clean:调用clean生命周期的clean阶段,实际执行 pre-clean 和 clean 阶段
    • (2) mvn test:调用default生命周期的test阶段
    • (3) mvn clean install:调用clean生命周期的clean阶段和default生命周期的install阶段

    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提供的命令行选项

    • --also-make 同时构建所列模块的依赖模块 、

    • --also-make-dependents 同时构建依赖于所列模块的模块、

    • --projects <arg> 构建指定的模块,使用逗号分隔、

    • --resume-from <arg> 从指定的模块恢复反应堆,在完整的反应堆基础上指定从哪个模块开始构建

    八、创建私服(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格式,因此也被省略

    • maven central仓库代理maven中央仓库,其策略为release,因此只会下载和缓存发布版本构件

    • releases:这是一个策略为release的宿主类型仓库,用来部署组织内部的发布版本构件

    • snapshots:宿主类型仓库

    • 3rd party:策略为release的宿主类型仓库,用来部署无法从公共仓库获得的第三方发布版本构件

    • public repositories:该仓库组将上述所有策略为release的仓库聚合并通过一致的地址提供服务

    • public snapshot repositories:

    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下载构件

    • 可以在pom中配置repository和pluginRepository,但这样的配置只对当前项目有效
    • 在settings中配置
    <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/下的所有符合命名模式的测试类,模式包括:

    • Test*.java

    • *Test.java

    • *TestCase.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. 动态指定要运行的测试用例:

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

    • -Dtest=xxxTest类,
    • test=Random*Test,还支持Class1,Class2指定多个类

    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个目标,分别为:

    • (1) release:prepare :这个目标将依次执行:检查项目是否有未提交的代码、检查项目是否有快照版本依赖、根据用户的输入将快照版本升级为发布版、将POM中的SCM信息更新为标签地址、基于修改后的POM执行maven构建、提交pom变更、基于用户输入为代码打标签、将代码从发布版升级为新的快照版、提交POM变更

    • (2) release:rollback :回退release:preare所执行的操作 将POM回退至release:prepare之前的状态,并提交 需要注意的是,该步骤不会删除release:prepare生成的标签,因此用户需要手动删除

    • (3) release:perform: 执行版本发布 签出release:prepare生成的标签中的源代码,并在此基础上执行mvn deploy命令打包并部署构件到仓库中

    要为项目发布版本,首先需要为其添加正确的版本控制系统信息,
    这是因为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>
    
    • connection表示一个只读的scm地址,
    • developerConnection表示可写的scm地址,
    • url表示可以在浏览器中访问的scm地址
    • Connection和developerConnection必须是scm开头,然后是版本控制工具类型,然后才是地址

    还需要配置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.xml
    • settings.xml

    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:

    相关文章

      网友评论

        本文标题:maven实战

        本文链接:https://www.haomeiwen.com/subject/sokxpxtx.html