maven权威指南读书笔记

mvn clean install -X


maven默认目录

maven,在没有自定义的情况下,源码假定在\${basedir}/src/main/java;资源文件假定在\${basedir}/src/main/resources;测试代码假定在\${basedir}/src/test;测试资源文件假定在\${basedir}/src/test/resources;编译好的字节码在\${basedir}/target/classes;可以分发的jar包在\${basedir}/target。
其中\${basedir}/src/main/java和\${basedir}/src/main/resources里的文件,打包后都在classpath目录下。

资源目录并非一定要放在src/main/resources下,假设有个项目包含数百个xml文档和数百个图片,可以创建两个目录src/main/xml和src/main/images,并且配置如下:
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
        </resource>
        <resource>
            <directory>src/main/xml</directory>
        </resource>
        <resource>
            <directory>src/main/images</directory>
        </resource>
    </resources>
</build>

超级pom里资源目录就是这样配置的。


超级pom是maven安装的一部分。settings.xml和pom.xml文件的配置可以覆盖超级pom的设置。


maven插件、目标

第一次使用全新的maven运行 mvn install命令的时候,它会从中央仓库下载大部分核心插件,然后存储在maven仓库里。

mvn help:describe -Dplugin=help
help是一个插件,describe是此插件的一个目标,使用-Dplugin指定想要查看的插件

mvn archetype:generate -DgroupId=com.sto -DartifactId=simple
接下来一路回车,就会生成一个maven项目
archetype,[ˈɑːkitaɪp],典型。archetype是“一个原始的模型或者类型”,maven有许多可用的archetype,从生成一个简单的Swing应用,到一个复杂的Web应用。
artifact [ˈɑːtɪfækt] 手工制品,这里是构件、项目的意思。
上面的命令默认使用maven-archetype-quickstart
 
mvn install
在包含pom.xml的目录下运行,打包应用

运行程序
java -cp target/simple-1.0-SNAPSHOT.jar com.sto.App

maven运行时,会根据pom.xml的设置来运行,pom.xml是有多个层级的,maven需要组合多个层级的pom文件。查看组合后的pom.xml文件:
mvn help:effective-pom
effective [ɪˈfektɪv] 有效的;实际的

maven插件是单个或多个maven目标的集合。maven插件有archetype、jar、compiler、surefire。
maven目标是一个明确的任务。compiler插件有compile目标,surefire插件有test目标。
目标可以通过配置属性来定义其行为,比如:mvn archetype:generate -DgroupId=com.sto -DartifactId=simple,配置了组Id和项目Id。


插件前缀

 mvn org.apche.maven.plugins:maven-jar-plugin:2.2:jar
 mvn jar:jar


生命周期和生命周期阶段

mvn package,package是一个生命周期阶段

maven有三个标准的生命周期,clean、default、site。
clean包含三个生命周期阶段,pre-clean、clean、post-clean。
default其中包含test、package、install、deploy这些阶段。deploy,复制包到远程maven仓库。

生命周期包含一系列有序的阶段,每个阶段可以绑定零个或多个目标,比如package生命周期阶段绑定了jar:jar插件目标;clean生命周期阶段绑定了clean插件的clean目标;site生命周期包含有site生命周期阶段,该阶段绑定了site插件的site目标

maven执行一个阶段时,会有序地执行前面的所有阶段,直到指定的那个阶段为止。
mvn package,相当于 mvn resources:resources compiler:compile resources:testResources compiler:testCompile surefire:test jar:jar

packaging有jar、war、maven-plugin。packaging是jar和war不同类型的构件,绑定在package生命周期阶段的插件目标也不同,有jar:jar,有war:war。


\${}的使用
maven有三个隐式的变量,env、project、settings。
\${env.PATH}
\${settings.offline}
\${project.groupId}


还可以在pom.xml或settings.xml中提供properties元素设置自己的属性。
<properties>
    <foo>bar</foo>
</properties>
\${project.foo}或\${foo}

还可以访问java系统属性,所有可以通过java.lang.System的getProperties()方法访问的属性,${user.name}


maven资源过滤

resources:resources目标首先过滤资源,然后将资源复制到输出目录。
就像在pom文件中使用\${}引用变量一样,也可以在资源文件中使用。
资源过滤即替换资源文件中的一些符号,与profile联系起来,就可以生成针对不同部署平台的构件;。
maven默认会跳过资源过滤,我们需要显示地配置资源过滤:

<build>
    <filters>
        <filter>src/main/my.properties</filter>
    </filters>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

1、建立一个maven项目
mvn archetype:generate -DgroupId=com.sto -DartifactId=simple
2、打开resources目录,随便自定义一个文件,取名service.xml,文件内容如下:
<service>
    <!-- ${project.version} -->
    <!-- ${env.PATH} -->
    <url>${jdbc.url}</url>
    <user>${jdbc.username}</user>
    <password>${jdbc.password}</password>
</service>
3、再建立一个my.properties文件,内容如下:
jdbc.url=jdbc:hsqldb:mem:mydb
jdbc.username=sa
jdbc.password=123
4、配置资源过滤
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
    <filters>
        <filter>src/main/my.properties</filter>
    </filters>
</build>
5、执行mvn package
6、查看target/classes/service.xml
一个示例
7、复制service.xml并粘贴,改名为service2.xml
8、只对某个资源过滤并复制输出到指定目录
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>service2.xml</include>
            </includes>
            <!-- 定义资源输出目录,可以不配置,默认输出到classPath -->
            <targetPath>${basedir}</targetPath>
            <filtering>true</filtering>
        </resource>
    </resources>
    <filters>
        <filter>src/main/my.properties</filter>
    </filters>
</build>
另一个示例

profile

profile是用来做什么的?它可以为特殊环境自定义特殊的构建。Maven能让你定义任意数量的profile,这些定义可以覆盖pom.xml中的任何配置。
你可以在开发profile中,访问本地数据库,在产品profile中,访问产品数据库。
profile也可以通过环境和平台被激活,你可以自定义一个profile,它根据不同的操作系统或不同的JDK版本有不同的行为。
profile激活元素可以包含一个或多个选择器:包含JDK版本,操作系统参数,文件,及maven属性。
maven3不再支持base目录下的profiles.xml文件。
可以在settings.xml中添加profiles元素。

<project>
    <profiles>
        <profile>
            <id>dev</id>
            <activation>
                <activeByDefault>false</activeByDefault>
                <jdk>1.5</jdk>
                <os>
                    <name>Windows XP</name>
                    <family>Windows</family>
                    <arch>x86</arch>
                    <version>5.1.2600</version>
                </os>
                <property>
                    <!-- maven属性 -->
                    <name>mavenVersion</name>
                    <value>2.0.5</value>
                </property>
                <file>
                    <!-- 在基础目录中存在及不存在file2和file1才可激活 -->
                    <exists>file2.properties</exists>
                    <missing>file1.properties</missing>
                </file>
            </activation>
        </profile>
    </profiles>
</project>    
View Code

示例:为生产环境和开发环境配置不同的profile

1、新建项目。mvn archetype:generate -DgroupId=com.sto -DartifactId=simple

2、添加资源文件。打开resources目录,新建自定义文件service.xml,文件内容:

<service>
    <env>${my.os}</env>
</service>

3、在main文件夹下新建文件夹config,添加文件 dev.properties,文件内容:my.os=win10。添加文件 pro.properties,文件内容 my.os=centos。

4、打开pom.xml,在build元素内添加:

    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>

在project元素内添加:

<profiles>
    <profile>
        <id>dev</id>
        <activation>
            <os>
                <name>Windows 10</name>
            </os>
        </activation>
        <build>
            <filters>
                <filter>src/main/config/dev.properties</filter>
            </filters>
        </build>
    </profile>
    <profile>
        <id>pro</id>
        <build>
            <filters>
                <filter>src/main/config/pro.properties</filter>
            </filters>
        </build>
    </profile>
  </profiles>
View Code

 5、执行mvn package,查看target里的service.xml文件;执行mvn package -Ppro,查看target里的文件service.xml


插件配置、目标配置、compiler插件配置

compile阶段绑定compiler插件的compile目标,compile目标会调用javac。
compiler插件假设所有的java源码遵循java 1.3,运行在java 1.1 JVM。
更改配置:
<build>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.5</source>
                <target>1.5</target>
            </configuration>
        </plugin>
    </plugins>
</build>
或者:
<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                        <configuration>
                            <source>1.5</source>
                            <target>1.5</target>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </pluginManagement>
</build>
建议使用第一种配置方式,第一种方式配置的是compiler插件,第二种方式配置的是compile目标。
我们为整个插件配置source和target,是因为compiler:compile并不是我们唯一感兴趣的目标,另外还有compiler:testCompile目标。
View Code

maven坐标可以唯一标识一个项目,或一个插件。maven的坐标有组id,项目id,版本号,classifier。classifier,发布同样的代码,但需要生成两个独立的包,就可以使用分类器,一个使用java1.4编译,一个使用java1.6编译。分类器常用于打包构件的源码、javaDoc或者二进制集合。


maven依赖的传递性,A项目依赖B项目,B项目又依赖C项目,我们在A项目的pom.xml文件里只需要添加对B项目的依赖即可。因为B项目也是一个maven项目,B项目的pom文件里已经定义了对C项目的依赖。


依赖范围控制依赖在哪些classpath中可用。
compile,默认范围,编译、测试、运行都依赖,所有的classpath中有。
test,只在测试编译和测试运行时在classpath中有效的依赖。
provided,servlet依赖已经由运行容器提供,不会被包含到war包中。
runtime,在运行和测试系统时需要。


mvn site
会生成htlm文件,可以查看依赖,查看项目信息,查看maven插件


mvn dependency:tree
查看依赖树


执行package生命周期阶段,如果surefire:test执行失败,默认会停止构建项目。
忽略测试失败配置
1、pom文件配置
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <testFailureIgnore>true</testFailureIgnore>
            </configuration>
        </plugin>
    </plugins>
</build>
2、命令行配置
mvn test -Dmaven.test.failure.ignore=true


跳过单元测试
1、pom文件配置
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <skip>true</skip>
            </configuration>
        </plugin>
    </plugins>
</build>

2、命令行配置
mvn install -Dmaven.test.skip=true


mvn Assembly插件用来创建应用程序的压缩包

<build>
    <plugins>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </plugin>
    </plugins>
</build>
mvn install assembly:assembly
示例一

示例二,将项目源码以压缩包的形式复制一份给别人
1、mvn archetype:generate -DgroupId=com.sto -DartifactId=simple
2、mvn assembly:single -DdescriptorId=project

示例三,创建一个可运行的jar文件

1、mvn archetype:generate -DgroupId=com.sto -DartifactId=simple
2、修改pom.xml
添加依赖,用以观察依赖被一起打包
 <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>commons-lang</groupId>
      <artifactId>commons-lang</artifactId>
      <version>2.4</version>
    </dependency>    
  </dependencies>
 配置assembly
 <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.2-beta-2</version>
        <executions>
          <execution>
            <id>create-executable-jar</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
            <configuration>
              <descriptorRefs>
                <descriptorRef>
                  jar-with-dependencies
                </descriptorRef>
              </descriptorRefs>
              <archive>
                <manifest>
                  <mainClass>com.sto.App</mainClass>
                </manifest>
              </archive>
           </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
 3、mvn package
 4、java -jar simple-1.0-SNAPSHOT-jar-with-dependencies.jar
 5、观察
 此jar包比标准生成的jar包大很多,因为此jar包内部还真实地包含了依赖;标准jar包只是通过pom文件声明了需要哪些依赖。
 此jar包的MANIFEST.MF文件中包含有主类位置——Main-Class: com.sto.App
View Code

示例四,通过套件依赖组装套件

 1、mvn archetype:generate -DgroupId=com.sto -DartifactId=simple;并删除src目录,只保留pom文件
 2、修改pom文件
 类型改为pom
  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <artifactId>maven-assembly-plugin</artifactId>
          <version>2.2-beta-2</version>
          <executions>
            <execution>
              <id>create-project-bundle</id>
              <phase>package</phase>
              <goals>
                <goal>single</goal>
              </goals>
              <configuration>
                <descriptorRefs>
                  <descriptorRef>project</descriptorRef>
                </descriptorRefs>
              </configuration>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
  3、新建两个子项目first、second
  mvn archetype:generate -DgroupId=com.sto -DartifactId=first
  mvn archetype:generate -DgroupId=com.sto -DartifactId=second
  4、修改first、second项目的pom文件
 <build>
  <plugins>
    <plugin>
      <artifactId>maven-assembly-plugin</artifactId>
    </plugin>
  </plugins>
</build>
 5、执行mvn install
 观察:maven把first、second两个项目的标准jar文件、pom文件、及项目压缩文件都复制到了maven仓库。
 6、创建一个新项目bundle,和simple并列关系或者说没有关系的项目
 mvn archetype:generate -DgroupId=com.bundle -DartifactId=bundle
 7、修改bundle的pom文件
 <packaging>pom</packaging>
 <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.sto</groupId>
      <artifactId>first</artifactId>
      <version>1.0-SNAPSHOT</version>
      <classifier>project</classifier>
      <type>zip</type>
    </dependency>
    <dependency>
      <groupId>com.sto</groupId>
      <artifactId>second</artifactId>
      <version>1.0-SNAPSHOT</version>
      <classifier>project</classifier>
      <type>zip</type>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.2-beta-2</version>
        <executions>
          <execution>
            <id>bundle-project-sources</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
            <configuration>
              <descriptorRefs>
                <descriptorRef>
                  jar-with-dependencies
                </descriptorRef>
              </descriptorRefs>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>  
  8、mvn package
View Code

mvn archetype:generate -DgroupId=com.sto -DartifactId=simple-webapp -DarchetypeArtifactId=maven-archetype-webapp

maven jetty插件配置
<build>
    <plugins>
        <plugin>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>maven-jetty-plugin</artifactId>
        </plugin>
    </plugins>
</build>
在命令行运行 mvn jetty:run
最后提示[INFO] Started Jetty Server就成功运行了
浏览器访问:localhost:8080/simple-webapp


优化依赖
dependencyManagement放在父pom,并声明依赖版本,这时不会把依赖添加进来。接着,在子模块里声明依赖时,不需要添加版本,会采用父pom里dependencyManagement内声明的版本。
<project>
<dependencyManagement>
    <dependency>
    </dependency>
</dependencyManagement>
</project>


优化插件
pluginManagement元素定义在父项目,子项目会继承。

maven-resources-plugin插件在父pom的pluginManagement元素里配置后,子项目不需要再次声明组织ID及项目ID。

maven-assembly-plugin插件在父pom的pluginManagement元素下配置后,还必需在子项目声明artifactId。

新建父项目a
1、mvn archetype:generate -DgroupId=a -DartifactId=a
2、删除src目录,修改pom文件packaging为pom。并修改为:
 <build>
    <pluginManagement>
      <plugins>
        <plugin>
            <artifactId>maven-resources-plugin</artifactId>
            <version>3.0.2</version>
            <configuration>
                <resources>
                    <resource>
                        <directory>src/main/config</directory>
                    </resource>
                </resources>
            </configuration>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
新建父项目b
3、mvn archetype:generate -DgroupId=b -DartifactId=b
4、新建src/main/resources/resource.txt,新建src/main/config/config.txt
5、b项目pom:
 <parent>
    <artifactId>a</artifactId>
    <groupId>a</groupId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <artifactId>b</artifactId>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
6、执行mvn clean package,查看target/classes文件夹


排除传递性依赖
<dependency>
    <groupId>xxx</groupId>
    <artifactId>a</artifactId>
    <version>1.0</version>
    <exclusions>
        <exclusion>
            <groupId>xxx</groupId>
            <artifactId>b</artifactId>
        </exclusion>
    </exclusions>
</dependency>
此项目依赖于a项目,a项目又依赖于b项目,这里排除了对b项目的依赖。


可选依赖
依赖范围和依赖传递的关系


maven版本管理
SNAPSHOT,开发版本,maven在安装或发布这个构件时会将该符号展开为一个日期和时间值,转换为UTC。
LATEST指仓库中构件的最新发布版或快照版,即最近部署的那个版本。
从maven 2.0.9开始,超级pom中锁住了一组核心插件的版本,提高了maven构建的稳定性。但非核心插件或者说没有在超级pom中指定版本的插件maven仍然会自动去仓库下载LATEST版本。不过,因为在超级pom中插件管理部分配置了不下载快照版本,插件更新策略也被设置为永不更新。所以实际上不会自动更新插件的。


聚集和继承。聚集用来模块构建;继承父文件内容。
maven执行带有子模块的项目时,首先载入父POM,然后定位所有子POM,然后把这些POM放入reactor(反应堆),reactor负责分析模块间的依赖关系,从而确保各模块能以适当的顺序被编译和安装。
POM最佳实践
如果你有一组逻辑上归类在一起的依赖,可以创建一个打包方式为pom的项目来将这些依赖集中在一起。比如,假设应用程序使用hibernate,所有使用hiberna的项目同时依赖Spring和MySql Jdbc驱动。这时,创建一个打包方式为pom的项目A,为其添加hibernate、spring、Mysql Jdbc的依赖。
之后,哪个项目需要这一组依赖,直接依赖项目A。
如果把A项目设置为父项目,不灵活,因为一个maven项目只能有一个父项目。

 

posted @ 2020-03-12 19:50  zhuangrunwei  阅读(218)  评论(0编辑  收藏  举报