美文网首页程序员
maven进阶插件

maven进阶插件

作者: icecrea | 来源:发表于2017-12-21 15:08 被阅读310次

    官方文档: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

    相关文章

      网友评论

        本文标题:maven进阶插件

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