• Maven学习补充笔记


    Maven可以称之为当前项目构建的事实上的标准了,基本上做的项目都是用Maven构建的。一直在使用Maven,但是没有较为全面地了解过,这篇博客主要记录之前使用过程中被忽略的部分,Maven的使用之前写过,传送门:Maven的学习

    Maven配置与安装

    Maven修改配置文件的最佳实践

    Maven的配置文件,位于Maven安装目录/conf/settings.xml 之前都是直接在这个文件中修改Maven配置,实际上这里的配置文件是全局配置,对于当前操作系统所有的用户生效,整台机器上所有用户都会直接受到该配置的影响。最佳实践是我们将这个配置文件拷贝放在 ~/.m2/settings.xml,(~ 表示C盘/user/用户目录)这是用户范围的设置,可以在不同用户之间形成不同配置,而且互不影响,不推荐直接修改Maven安装目录下的文件,包括全局settings.xml

    这样的配置还有一个好处就是,方便Maven升级,直接修改conf目录下的settings.xml,当升级Maven版本后还需要记得修改新的settings.xml,如果使用 ~/.m2目录下的settings.xml就不需要了

    验证Maven是否安装成功

    当解压Maven,配置环境变量,修改settings.xml之后推荐使用如下命令验证

    mvn help:system
    

    这个命令通过使用Maven的help插件输出当前系统的信息,如果没有help插件会要求联网从仓库中下载,所以推荐将这个命令作为安装Maven后的第一个命令用于验证。mvn -v命令可以验证Maven是否安装成功,环境变量是否安装成功,但是对于settings.xml的修改没法验证

    修改Maven compiler编译的Java版本

    通常Maven编译插件支持的版本较低,同时推荐显式指定Java编译版本,可以参看如下配置

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

    命令行使用Archetype生成项目骨架

    这里记录下项目骨架命令

    mvn archetype:generate
    

    接下来会要求输入项目骨架编号

    接下来输入groupId,artifactId,version以及包名package即可

    打包一个可运行的jar

    默认打包生成jar是不能直接运行的,因为带有main方法的类信息不会添加到manifest中(打开jar文件中的META/MANIFEST.MF文件无法看到Main-Class),为了生成可执行的jar文件,需要借助maven-shade-plugin,配置如下

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>shade</goal>
                </goals>
                <configuration>
                    <transformers>
                        <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                            <mainClass>Main方法所在类的全路径</mainClass>
                        </transformer>
                    </transformers>
                </configuration>
            </execution>
        </executions>
    </plugin>
    

    这样打出来的jar是带有Main-Class信息的可执行jar,使用java -jar即可运行

    依赖

    排除依赖

    因为依赖传递的问题,可能因为某些原因传递过来的版本不稳定或者想要指定某个版本,可以使用<exclusions>标签排除某些传递的jar,这也是解决jar冲突的一种方案

     <dependency>
        <groupId>com.lynu</groupId>
        <artifactId>project-a</artifactId>
        <version>1.0.0</version>
        <exclusions>
            <exclusion>
                <groupId>com.lynu</groupId>
                <artifactId>project-b</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    

    这样在当前项目中使用project-a的时候,就把其所依赖的project-b给排除了

    exclusions可以有多个exclusion元素排除多个依赖,声明exclusion元素只需要groupIdartifactId即可,因为只需要groupIdartifactId就可以唯一定位依赖

    可选依赖

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    

    dependency元素有一个optional属性,该属性可以指定这个依赖是可选依赖,可选依赖的jar只对当前项目可以使用,如果当前项目作为其他项目的依赖jar,则其他项目不能通过传递得到这个可选依赖,如果需要使用就要显式声明

    仓库

    配置远程仓库

    Maven中仓库只分为本地仓库和远程仓库,远程仓库包括:中央仓库,私服以及其他公共仓库

    本地仓库默认会在~/.m2/respository目录下,该目录一般位于c盘,如果需要自定义的话可以编辑settings.xml文件设置localRepository元素的值即可。而配置远程仓库,可以在项目的POM中配置

    <repositories>
        <repository>
            <id>jboss</id>
            <name>JBoss Repository</name>
            <url>http://repository.jboss.com/maven2/</url>
            <releases>
                <!--是否下载releases发布版构件-->
                <enabled>true</enabled>
                <!--更新频率-->
                <updatePolicy>daily</updatePolicy>
                <!--检查校验文件的策略-->
                <checksumPolicy>ignore</checksumPolicy>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <!--仓库文件布局, default表示使用的是Maven2及Maven3的默认布局, 而不是Maven1的布局-->
            <layout>default</layout>
        </repository>
    </repositories>
    

    updatePolicy:配置Maven从远程仓库检查更新的频率。默认值daily-每天,其他可用值 never-从不检查更新 always-每次构建时检查更新 interval:X-每隔X分钟检查更新(X为整数)
    checksumPolicy:配置Maven检查校验文件的策略。Maven在下载构建或者部署构建到仓库中时,会校验对应的文件,如果校验失败,就会采用配置的策略。默认值warn-校验失败输出警告信息,其他可选值 fail-校验失败停止构建 ignore-完全忽略校验和错误

    将jar部署到远程仓库都在Maven的学习中有记录

    远程仓库的认证

    如果远程仓库需要用户名,密码任何认证,就需要配置认证信息了。认证信息与配置远程仓库信息不同,仓库信息可以直接配置到POM文件中,但是认证信息必须配置到settings.xml文件中。这是因为POM文件会被提交到SVN/GIT代码仓库中,而settings.xml在本机,出于安全性考虑

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

    id必须与POM中远程仓库的id完全一致,正是这个id将认证信息与仓库配置联系在一起

    一些仓库搜索服务

    直接去中央仓库中找需要的jar不太明智,可以使用一些带有搜索服务的Maven服务,例如MVNrepository

    继承与聚合

    Maven的继承与聚合,实际上是两个不同的概念,聚合:将多个module模块聚集在一起形成一个统一的项目;继承:作为父工程定义一些属性供子工程复用。实际开发中经常将这个两个概念统一在父工程中。父工程只包含一个type为pom的POM.xml文件, 对子工程进行依赖与插件管理。记录一个通用的父工程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>xxx</groupId>
        <artifactId>xxx</artifactId>
        <packaging>pom</packaging>
    	<name>XXX Project</name>
        <version>1.0-SNAPSHOT</version>
    	
        <!--定义自定义属性-->
        <properties></properties>
    	
        <!--聚合其他模块-->
        <modules>
            <module>xxx</module>
        </modules>
    	
        <!--依赖管理,并不会真正引入依赖-->
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId></groupId>
                    <artifactId></artifactId>
                    <version></version>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <!--插件管理,并不会真正引入插件-->
        <build>
            <pluginManagement>
                <plugins>
                    <plugin>
                        <groupId></groupId>
                        <artifactId></artifactId>
                        <version></version>
                    </plugin>
                </plugins>
            </pluginManagement>
        </build>
    
    </project>
    

    在父工程进行依赖管理和插件管理,更多的是在限定使用的版本,而且也没有真实引入插件和依赖,真正引入插件和依赖的地方还是在子工程中,而且子工程中也可以引入不同版本的依赖/插件,或者引入父工程中没有Manager的依赖/插件

    当在其他项目中需要使用父工程依赖/插件一样的配置,可以使用import范围依赖将这一个配置导入

    <dependencyManagement>
    	<dependencies>
    		<dependency>
    			<groupId>存在依赖/插件管理的groupId</groupId>
    			<artifactId>存在依赖/插件管理的artifactId</artifactId>
    			<version>存在依赖/插件管理的version</version>
    			<type>pom</type>
    			<scope>import</scope>
    		</dependency>
    	</dependencies>
    </dependencyManagement>
    

    子工程pom.xml文件中使用parent标签引入父工程坐标形成继承

    <parent>
            <groupId></groupId>
            <artifactId></artifactId>
            <version></version>
            <!--relativePath用于指定父工程的POM.xml文件位置 相对路径 默认位置../pom.xml 如果路径不同使用该标签修改-->
            <!--<relativePath></relativePath>-->
    </parent>
    

    只构建指定模块

    但项目比较庞大,而且模块众多,一次构建所有模块费时费力,这个时候可以指定所需模块,利用Maven的参数即可,因为模块之间存在依赖关系,构建时必须存在先后顺序,这种关系在Maven中称之为反应堆

    • -am:--also make 同时构建所指定的模块及依赖模块
    • -amd:--also-make-dependents 同时构建依赖于该模块的模块
    • -pl:--projects 构建指定的模块,模块之间使用逗号分隔
    • -rf:--resume-from 在反应堆构建顺序基础上指定从哪个模块开始构建

    以上几个参数可以组合使用,例如:编译xxx模块,并先构建其依赖的模块(不然xxx模块无法使用)

    mvn clean package -pl xxx -am
    

    超级POM

    所有pom.xml文件都默认继承一个超级POM文件,这个文件中指定了一些常用插件的版本,项目源码,配置文件,测试代码/配置文件都路径,项目构建路径等信息,这样的方式是Maven约定优于配置理念的提现,这个超级POM文件位于:$MAVEN_PATH/lib/maven-model-builder-x.x.x.jar中的org/apache/maven/model/pom-4.0.0.xml路径下

    所有的约定都在这里配置的,如果不想遵循约定(强烈不推荐),例如约定源码目录是:src/main/java,我们希望改为src/java,就需要在项目的pom.xml中的build元素中修改

    <build>
        <sourceDirectory>src/java</sourceDirectory>
    <build>
    

    测试

    跳过测试

    测试作为项目构建中很重要的一步,理论上不应该跳过测试,只有测试通过之后的才会进行打包,安装等后续操作,这样也保证了项目的稳定。但是运行测试代码需要较长耗时,而且有些错误的单元测试没有得到修正,所以我们希望可以跳过测试。跳过方法两种

    1. 通过命令行参数skipTests
    mvn package -DskipTests
    

    这个指令可以跳过测试运行2,但是测试代码还是会进行编译,同样会消耗大量的时间

    mvn package -Dmaven.test.skip=true
    

    这样就可以连测试代码编译过程也跳过了

    通过命令行参数的方式是一种临时配置,只在当前执行中生效

    1. 通过Maven插件参数配置
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.5</version>
        <configuration>
            <skipTests>true</skipTests>
        </configuration>
    </plugin>
    

    这样的配置等同于mvn package -DskipTests,不同在于通过插件的配置让项目长时间跳过测试

    同样的,想要跳过测试代码的编译过程,如下配置

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.1</version>
        <configuration>
            <skip>true</skip>
        </configuration>
    </plugin>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.5</version>
        <configuration>
            <skipTests>true</skipTests>
        </configuration>
    </plugin>
    

    同样对应命令mvn package -Dmaven.test.skip=true

    指定要运行的测试用例

    maven-surefire-plugin提供了test参数让Maven用户能够在命令行指定要运行的测试用例

    mvn test -Dtest=MyTest
    

    可以使用*星号匹配零个或多个字符,如果指定多个测试用例,可以使用,逗号分隔

    test参数必须匹配一个或多个测试类,如果没有就会报错,这时可以设置-DfailIfNoTests=false告诉maven-surefire-plugin即使没有任何测试也不要报错

    mvn test -Dtest -DfailIfNoTests=false
    

    包含与排除测试用例

    默认情况下,在测试目录下所有以Test结尾的类都会当作测试用例,我们一般遵循这个规范就可,但是有的测试类是以Tests结尾的,这时就需要我们主动包含这样的测试用例

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.5</version>
        <configuration>
            <includes>**/*Tests.java</includes>
        </configuration>
    </plugin>
    

    **表示任意路径,一个星号*匹配0个或多个字符

    如果需要排除一些测试用例,可以使用excludes元素

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.22.2</version>
        <configuration>
            <excludes>**/*TempDemoTest</excludes>
        </configuration>
    </plugin>
    

    打包测试代码

    一般来说测试代码是不会打包的,但是如果需要的话,也是可以办到的,通过配置maven-jar-plugin

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>2.2</version>
        <executions>
            <execution>
                <goals>
                    <goal>test-jar</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
    

    这样在Maven的生命周期package阶段就会对测试代码打包,形成类似xxx-tests.jar文件,但这个文件部署到仓库中之后,就可以通过依赖声明了

    <dependency>
        <groupId>com.test</groupId>
        <artifactId>myTest</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <type>test-jar</type>
        <scop>test</scop>
    </dependency>
    

    与一般的以来不同的是,这里使用了特殊的元素type,而去测试包只能使用特殊的test-jar类型

    web容器插件

    配置jetty插件

    <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>7.6.16.v20140903</version>
        <configuration>
            <scanIntervalSeconds>10</scanIntervalSeconds>
            <webAppConfig>
                <contextPath>/test</contextPath>
            </webAppConfig>
        </configuration>
    </plugin>
    

    scanIntervalSeconds表示扫描项目变更的时间间隔,这里配置的是每隔10秒,默认值是0,表示不扫描,配置这个值可以实现类似热部署的功能
    contextPath 表示项目部署之后的context path 例如这里:http://hostname:port/test/访问应用

    在启动之前可以对setting.xml文件进行一个小修改(可选)。因为默认情况下,只有org.apache.maven.pluginsorg.codehaus.mojo两个groupId的插件才可以支持简化命令行调用

    <setting>
      <pluginGroup>
        <pluginGroup>org.mortbay.jetty</pluginGroup>
      </pluginGroup>
    </setting>
    

    现在可以在命令行中使用如下命令启动jetty-maven-plugin

    mvn jetty:run
    

    jetty 默认监听本地8080端口,如果使用其他端口,可以添加jetty.port参数

    mvn jetty:run -Djetty.port=9090
    

    配置tomcat插件

    <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
            <port>8080</port>
        </configuration>
    </plugin>
    

    运行tomcat7插件的命令如下

    mvn tomcat7:run
    

    因为这个插件有很长时间没有更新了,所以不是很推荐使用,不如直接部署到tomcat容器中,还可以挑选指定的tomcat版本

    Maven属性

    Maven的属性有6类,这些属性就相当于Maven中的变量。分别为

    • 内置属性:主要有两个内置属性, ${basedir}表示项目根目录,即包含pom.xml文件所在的目录;${version}表示项目的版本号
    • POM属性:可以适用该类属性应用POM文件中对应元素的值。例如${project.artifactId}对应<project><artifactId>元素的值。常用的POM属性有
      • ${project.build.sourceDirectory}: 项目的主源码目录,默认为src/main/java
      • ${project.build.testSourceDirsctory}:项目的测试源码目录,默认为src/test/java
      • ${project.directory}:项目构建输出目录,默认为target
      • ${project.outputDirectory}:项目主代码输出目录,默认为target/classes
      • ${project.testOutputDirectory}:项目测试代码编译输出目录,默认为target/test-classes
      • ${project.groupId}:项目的GroupId
      • ${project.artifactId}:项目的ArtifactId
      • ${project.version}:项目的version, 与${version}等价
      • ${project.build.finalName}:项目打包输出文件的名称,默认为${project.artifactId}-${project.version}
    • 自定义属性,这个应该是最为常见的,用户可以在POM的<projects>元素下自定义Maven属性,例如
    <project>
     <properties>
      <my.prop>hello</my.prop>
     </properties>
    </project>
    

    然后在POM中使用${my.prop}的时候就会被自动替换为hello

    • Settings属性:用户可以在settings.开头的属性引用settins.xml文件中XML元素的值,比较常用的${settings.localRepository}指向用户本地仓库地址
    • Java系统属性:所有Java系统属性都可以被Maven属性引用,例如${user.home}指向了用户目录,用户可以使用mvn help:system参看所有的Java系统属性
    • 环境变量属性:所有环境变量都可以使用以env.开头的Maven属性引用。例如${env.JAVA_HOME}指向了JAVA——HOME环境变量的值,用户可以使用mvn help:system参看所有的环境变量

    利用这些属性可以更好地简化POM的配置,例如在多模块项目中,模块之间以来比较常见,这些模块之间一般都是相同的groupId和version,因此就可以如下利用POM属性配置

    <dependency>
        <groupId>${project.groupId}</groupId>
        <artifactId>dao</artifactId>
        <version>${project.version}</version>
    </dependency>
    <dependency>
        <groupId>${project.groupId}</groupId>
        <artifactId>util</artifactId>
        <version>${project.version}</version>
    </dependency>
    
  • 相关阅读:
    Codeforces ECR 83 C. Adding Powers (位运算)
    Codeforces Round #636div3 D. Constant Palindrome Sum (划分区间,差分)
    Codeforces Round #603 C. Everyone is a Winner!
    Centos7 下搭建SVN + Apache 服务器 风行天下
    完整部署CentOS7.2+OpenStack+kvm 云平台环境(1)基础环境搭建 风行天下
    云计算的理解 风行天下
    Python之路3【知识点】白话Python编码和文件操作 风行天下
    C#中TreeView组件使用方法初步
    复制文件时explorer.exe出错解决方法
    C# 里TreeView绑定数据库实现分类
  • 原文地址:https://www.cnblogs.com/lz2017/p/12995177.html
Copyright © 2020-2023  润新知