maven进阶插件

官方文档:http://maven.apache.org/guides/introduction/introduction-to-plugins.html


父子项目都设置properties,子项目会覆盖父项目。
但是使用的jar包要覆盖全,比如logback有classic和core两个模块,之前只覆盖了classic模块,没有添加core的依赖。导致logback两个版本不一致,一个是子项目的properties,一个来自父项目报错。

          <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>${org.slf4j}</version>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
                <version>${ch.qos.logback}</version>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>${ch.qos.logback}</version>
            </dependency>

同时依赖范围scope也是以当前项目为准,覆盖父pom


作用域

compile
默认就是compile,什么都不配置也就是意味着compile。compile表示被依赖项目需要参与当前项目的编译,当然后续的测试,运行周期也参与其中,是一个比较强的依赖。打包的时候通常需要包含进去。

test
表示依赖项目仅仅参与测试相关的工作,包括测试代码的编译,执行。比较典型的如junit。
(只是测试代码的编译。test目录下,在java目录下无法使用)

runntime
运行时依赖范围。使用此依赖范围的Maven依赖,对于测试和运行classpath有效,但在编译主代码时无效。典型的例子是JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体JDBC驱动。(编译阶段需要的不能设置runtime,一个应用还有日志打印,slf4j设置为compile,而logback设置为runtime)

provided
意味着打包的时候可以不用包进去。使用此依赖范围的Maven依赖,对于编译和测试classpath有效,但在运行时无效。典型的例子是servlet-api,编译和测试项目的时候需要该依赖,但在运行项目的时候,由于容器已经提供,就不需要Maven重复地引入一遍。


打包注意事项

maven打包的时候默认是不加入依赖的jar包的,所以想打出一个独立的可运行jar包的话直接mvn clean install package是不行的。
用java -jar xxx.jar执行运行jar文件,会出现"no main manifest attribute, in xxx.jar"(没有设置Main-Class)、ClassNotFoundException(找不到依赖包)等错误。
要想jar包能直接通过java -jar xxx.jar运行,需要满足:
1、在jar包中的META-INF/MANIFEST.MF中指定Main-Class,这样才能确定程序的入口在哪里;
2、要能加载到依赖包。

解决方案之一: 添加下面jar,dependency两个插件
    <build>
        <plugins>
      <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                            <mainClass>com.qunar.Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.10</version>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

maven-jar-plugin用于生成META-INF/MANIFEST.MF文件的部分内容,<mainClass>com.xxg.Main</mainClass>指定MANIFEST.MF中的Main-Class,<addClasspath>true</addClasspath>会在MANIFEST.MF加上Class-Path项并配置依赖包,<classpathPrefix>lib/</classpathPrefix>指定依赖包所在目录。

例如下面是一个通过maven-jar-plugin插件生成的MANIFEST.MF文件片段:

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: icecrea
Class-Path: lib/guava-20.0.jar lib/slf4j-api-1.7.21.jar lib/logback-cl
 assic-1.1.7.jar lib/logback-core-1.1.7.jar
Created-By: Apache Maven 3.0.5
Build-Jdk: 1.8.0_152
Main-Class: com.qunar.Main

只是生成MANIFEST.MF文件还不够,maven-dependency-plugin插件用于将依赖包拷贝到<outputDirectory>${project.build.directory}/lib</outputDirectory>指定的位置,即lib目录下。
配置完成后,通过mvn package指令打包,会在target目录下生成jar包,并将依赖包拷贝到target/lib目录下,目录结构如下:


方案二:使用assembly插件(后面会具体介绍)

可以直接java -jar xx运行,但是在这里我如果自定义assembly.xml没有跑成功,显示找不到主类。有知道的希望可以说一下。

  <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.2.1</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.qunar.Main</mainClass>
                        </manifest>
                    </archive>
                    <!--<descriptors>-->
                        <!--<descriptor>src/main/resources/assembly.xml</descriptor>-->
                    <!--</descriptors>-->
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin> 

打包插件assembly

官网:http://maven.apache.org/plugins/maven-assembly-plugin/assembly.html

maven-assembly-plugin的用途是制作项目分发包,该分发包可能包含了项目的可执行文件、源代码、readme、平台脚本等等。maven-assembly-plugin支持各种主流的格式如zip、tar.gz、jar和war等,具体打包哪些文件是高度可控的,例如用户可以按文件级别的粒度、文件集级别的粒度、模块级别的粒度、以及依赖级别的粒度控制打包,此外,包含和排除配置也是支持的。maven-assembly-plugin要求用户使用一个名为assembly.xml的元数据文件来表述打包,它的single目标可以直接在命令行调用,也可以被绑定至生命周期。

pom文件配置

   <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.2.1</version>
                <configuration>
                    <descriptors>
                        <descriptor>src/main/resources/assembly.xml</descriptor>
                    </descriptors>
                    <!--<descriptorRefs>-->
                        <!--<descriptorRef>jar-with-dependencies</descriptorRef>-->
                    <!--</descriptorRefs>-->
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

assembly.xml文件配置
<useProjectArtifact>:
true表示将本项目也打成Jar包,添加到依赖文件夹下。对于下面则是Lib下多一个该项目的Jar包。

<dependencySets>
必须设置输出的文件目录,不然会报错,提示至少有一个目录

<fileSet>
<directory>src/main/java</directory>
<outputDirectory>/</outputDirectory>
</fileSet> :
fileSets允许用户通过文件或目录的粒度来控制打包。表示将该位置代码打包、如果不设置不会打包该目录代码(这里指jar包情况)

<baseDirectory>/haha</baseDirectory>:
这个可以设置打包目录的命名。如果下面xml加上这个,文件就变成了/haha/lib/... 这种形式。注意:这个是在 <includeBaseDirectory>true</includeBaseDirectory>设置为true的前提下,如果为false,打包结果目录名还是lib,
即<outputDirectory>lib</outputDirectory>(选项默认为true)

<assembly>
    <id>assembly</id>
    <formats>
        <format>zip</format>
    </formats>
    <includeBaseDirectory>true</includeBaseDirectory>
    <dependencySets>
        <dependencySet>
            <useProjectArtifact>true</useProjectArtifact>
            <outputDirectory>lib</outputDirectory>
        </dependencySet>
    </dependencySets>
    <fileSets>
        <fileSet>
            <outputDirectory>/</outputDirectory>
            <includes>
                <include>/readme.md</include>
            </includes>
        </fileSet>
        <fileSet>
               <directory>src/main/java</directory>
               <outputDirectory>/</outputDirectory>
        </fileSet>
    </fileSets>
</assembly>

打包目录结果如下



其他插件

maven-archetype-plugin
Maven命令mvn archetype:generate,这实际上就是让maven-archetype-plugin生成一个很简单的项目骨架,帮助开发者快速上手

maven-dependency-plugin
maven-dependency-plugin最大的用途是帮助分析项目依赖,dependency:list能够列出项目最终解析到的依赖列表,dependency:tree能进一步的描绘项目依赖树,dependency:analyze可以告诉你项目依赖潜在的问题,如果你有直接使用到的却未声明的依赖,该目标就会发出警告。maven-dependency-plugin还有很多目标帮助你操作依赖文件,例如dependency:copy-dependencies能将项目依赖从本地Maven仓库复制到某个特定的文件夹下面。

maven-enforcer-plugin
在一个稍大一点的组织或团队中,你无法保证所有成员都熟悉Maven,那他们做一些比较愚蠢的事情就会变得很正常,例如给项目引入了外部的SNAPSHOT依赖而导致构建不稳定,使用了一个与大家不一致的Maven版本而经常抱怨构建出现诡异问题。maven-enforcer-plugin能够帮助你避免之类问题,它允许你创建一系列规则强制大家遵守,包括设定Java版本、设定Maven版本、禁止某些依赖、禁止SNAPSHOT依赖。只要在一个父POM配置规则,然后让大家继承,当规则遭到破坏的时候,Maven就会报错。除了标准的规则之外,你还可以扩展该插件,编写自己的规则。maven-enforcer-plugin的enforce目标负责检查规则,它默认绑定到生命周期的validate阶段。

maven-help-plugin
maven-help-plugin是一个小巧的辅助工具,最简单的help:system可以打印所有可用的环境变量和Java系统属性。help:effective-pom和help:effective-settings最为有用,它们分别打印项目的有效POM和有效settings,有效POM是指合并了所有父POM(包括Super POM)后的XML,当你不确定POM的某些信息从何而来时,就可以查看有效POM。有效settings同理,特别是当你发现自己配置的settings.xml没有生效时,就可以用help:effective-settings来验证。此外,maven-help-plugin的describe目标可以帮助你描述任何一个Maven插件的信息,还有all-profiles目标和active-profiles目标帮助查看项目的Profile。

maven-surefire-plugin
http://maven.apache.org/plugins/maven-surefire-plugin
可能是由于历史的原因,Maven 2/3中用于执行测试的插件不是maven-test-plugin,而是maven-surefire-plugin。其实大部分时间内,只要你的测试类遵循通用的命令约定(以Test结尾、以TestCase结尾、或者以Test开头),就几乎不用知晓该插件的存在。然而在当你想要跳过测试、排除某些测试类、或者使用一些TestNG特性的时候,了解maven-surefire-plugin的一些配置选项就很有用了。例如
mvn test -Dtest=FooTest 这样一条命令的效果是仅运行FooTest测试类,这是通过控制maven-surefire-plugin的test参数实现的。

jetty-maven-plugin
http://wiki.eclipse.org/Jetty/Feature/Jetty_Maven_Plugin
在进行Web开发的时候,打开浏览器对应用进行手动的测试几乎是无法避免的,这种测试方法通常就是将项目打包成war文件,然后部署到Web容器中,再启动容器进行验证,这显然十分耗时。为了帮助开发者节省时间,jetty-maven-plugin应运而生,它完全兼容 Maven项目的目录结构,能够周期性地检查源文件,一旦发现变更后自动更新到内置的Jetty Web容器中。做一些基本配置后(例如Web应用的contextPath和自动扫描变更的时间间隔),你只要执行mvn jetty:run,然后在IDE中修改代码,代码经IDE自动编译后产生变更,再由jetty-maven-plugin侦测到后更新至Jetty容器,这时你就可以直接测试Web页面了。需要注意的是,jetty-maven-plugin并不是宿主于Apache或Codehaus的官方插件,因此使用的时候需要额外的配置settings.xml的pluginGroups元素,将org.mortbay.jetty这个pluginGroup加入。

tomcat7插件
直接执行mvn tomcat7:run

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

插件的两种调用方式

Maven本质上是一个插件框架,它的核心并不执行任何具体的构建任务,所有这些任务都交给插件来完成,例如编译源代码是由maven- compiler-plugin完成的。进一步说,每个任务对应了一个插件目标(goal),每个插件会有一个或者多个目标,例如maven- compiler-plugin的compile目标用来编译位于src/main/java/目录下的主源码,testCompile目标用来编译位于src/test/java/目录下的测试源码。

插件的两种调用方式:

  1. 将插件目标与生命周期阶段(lifecycle phase)绑定,这样用户在命令行只是输入生命周期阶段而已,例如Maven默认将maven-compiler-plugin的compile目标与compile生命周期阶段绑定,因此命令mvn compile实际上是先定位到compile这一生命周期阶段,然后再根据绑定关系调用maven-compiler-plugin的compile目标。
  2. 是直接在命令行指定要执行的插件目标,例如mvn archetype:generate 就表示调用maven-archetype-plugin的generate目标,这种带冒号的调用方式与生命周期无关。

常用插件官网:http://maven.apache.org/plugins/index.html


左侧是phase,右侧是对应绑定的goal.



相关命令

-e,-U,-X什么含义 打印异常/强制拉取最新的snapshot依赖,更新依赖/开启debug模式

maven命令执行单元测试 / 单元测试逻辑不编译,不执行,直接跳过 / 单元测试编译,只跳过测试过程
mvn test | mvn test -Dmaven.test.skip=true | mvn test -DskipTests

相关博客:
http://blog.csdn.net/onlyqi/article/details/6801318
http://www.infoq.com/cn/news/2011/04/xxb-maven-7-plugin?utm_source=infoq&utm_campaign=user_page&utm_medium=link

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 76,477评论 13 117
  • 转自:http://www.cnblogs.com/crazy-fox/archive/2012/02/09/23...
    晴天哥_374阅读 1,408评论 2 25
  • 我们都知道Maven本质上是一个插件框架,它的核心并不执行任何具体的构建任务,所有这些任务都交给插件来完成,例如编...
    付鹏丶阅读 937评论 0 15
  • 使用指导 如何添加外部依赖jar包 在Maven工程中添加依赖jar包,很简单,只要在POM文件中引入对应的<de...
    静默虚空阅读 1,575评论 0 13
  • 1.十年之前我认识了你,你认识了我 偶然的朋友圈一张你的照片,是你妈妈晒的,不得不说你真的没有小时候好看了。我...
    莫西仍然阅读 102评论 0 2