zoukankan      html  css  js  c++  java
  • maven系列(六)聚合与继承(还有TODO)

    第8章 聚合与继承

    Maven的聚合特性能够把项目的各个模块聚合在一起构建,而maven的继承特性则能帮助抽取各模块相同的依赖和插件等配置,在简化POM的同时,还能促进各个模块配置的一致性。

    8.1 mirana-dal

    mirana-dal模块负责mirana的数据的持久化,以json文件的形式保存数据,并支持账户的创建、读取、更新、删除等操作。

    【由于腾讯云那个mysql很难装,暂时又不想深入学习mongo,因此这个地方直接使用文件系统作为数据库,顺便学习java的IO知道,代码参考spring-core里面的io部分】

    相关类和方法有

    1. java.util.Properties(在项目内部)
    2. io和nio相关知识(更多见NIO)
    <?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">  
    <parent>
            <artifactId>mirana-parent</artifactId>
            <groupId>com.ssozh</groupId>
            <version>1.0.0-SNAPSHOT</version>
        </parent>
        
        
        <build>
            <testResources>
                <testResource>
                    <directory>src/test/resources</directory>
                    <filtering>true</filtering>
                </testResource>
            </testResources>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.1</version>
                    <configuration>
                        <source>${maven.compiler.source}</source>
                        <target>${maven.compiler.target}</target>
                    </configuration>
                </plugin>
    
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.2.0</version>
                    <configuration>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    

    该模块坐标为com.ssozh:mirana-parent:1.0.0-SNAPSHOT。和其他模块有相同的groupId,artifactId有相同的前缀。

    一般来说,一个项目的子模块都应该使用相同的groupid,如果在一起开发和发布,还应该使用相同的version。artifactId也应该有相同的前缀,以方便其他项目区分。

    build元素他包含了一个testResource子元素,这是为了开启资源过滤。【用于单元测试】。下面还包含两个插件,一个是maven-compiler-plugin用于支持java1.8(实际上该版本在超级POM中有设定,而这个1.8是在springboot-start-parent中设定的),此外还配置了maven-resources-plugin使用了UTF-8编码处理资源文件。

    8.2 聚合

    到目前为止,mirana这个项目分别在biz层实现了createGroup方法,和dal层的createGroup方法。这时,一个简单的需求就会自然而然地显示出来:我们会想要一次构建两个项目,而不是到两个模块的目录下分别执行mvn命令。

    为了能够使用一条命令就能够构建mirana-api、mirana-controller、mirana-common、mirana-dal等多个模块,我们需要额外创建一个名为mirana-parent的模块,然后通过该模块构建整个项目的所有模块。mirana-parent本身作为一个maven项目,它必须要有自己的POM,不过同时作为一个聚合项目,其POM又有特殊的地方,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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.5.4</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
        <groupId>com.ssozh</groupId>
        <artifactId>mirana-parent</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <name>mirana-parent</name>
    
        <description>Demo project for Spring Boot</description>
    
        <packaging>pom</packaging>
    
        <modules>
            <module>assembly</module>
            <module>controller</module>
            <module>service</module>
            <module>biz</module>
            <module>dal</module>
            <module>common</module>
            <module>integration</module>
            <module>api</module>
            <module>starter</module>
            <module>test</module>
        </modules>
    
    </project>
    

    这里有几个特殊的地方:

    1. packaging:pom,聚合模块的打包方式必须是pom,否则就无法构建
    2. modules:实现聚合的最核心位置,用户可以通过自一个打包方式为pom的maven项目中声明任意数量的module元素来实现模块的聚合。
    3. 一般来讲,模块所处的目录名称应该遇其artifactId一致,如果不一致,则需要将聚合pom中的<module>改成相应的目录名。
    4. 聚合模块与其他模块的目录结构并非一定要是父子关系,也可以使用平行目录结构,这个时候,<module>也应该指向正确的模块目录
    5. mvn clean install的过程:
      1. 解析聚合模块的POM,分析要构建的模块
      2. 计算出一个反应堆构建顺序(reactor build order)
        1. 这个就是依赖关系:parent->api->common->integration->dal->biz->service->controller->starter->assembly
      3. 根据这个顺序依次构建各个模块。
      4. 其他:上述过程中输出的是各个模块的名称,而不是artifactId。

    8.3 继承

    可以通过继承抽取出重复的配置,maven也有这种继承机制。

    作为父模块的POM和聚合模块的POM一样都必须是POM的打包类型。由于父模块不仅仅是为了帮助消除配置的重复,因为他本身不包含POM以外的项目文件,也就不需要src/main/java之类的文件夹了。

    relativePath表示父模块POM的相对路径,默认值是../pom.xml,其他情况需要手动写入。

    如果开发团队需要从源码库中迁出一个包含父子关系的Maven项目,则需要设置正确的<relativePath>

    8.3.1可继承的POM元素

    从上一节我们看到,groupId和version是可以被继承的,以下是完整的继承列表:

    • groupId:项目组Id,坐标核心元素。
    • version:项目版本,坐标核心元素。
    • properties:自定义Maven属性
    • dependencies:项目的依赖配置
    • dependencyManagement:项目的依赖管理配置
    • repositories:项目的仓库配置
    • build:包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等。
    • reporting:包括项目的报告输出目录配置、报告插件配置等。
    • description:项目的描述信息
    • organization:项目的组织信息。
    • inceptionYear:项目的创始年份
    • url:项目的url地址
    • developers、contributors:项目的开发者贡献值信息
    • distributionManagement:项目的部署配置
    • ciManagement:项目的持续集成系统信息
    • scm:项目的版本控制系统信息

    8.3.2 依赖管理(常用)

    Maven提供的dependencyManagement元素能够让子模块依赖父模块的依赖配置,又能保证子模块依赖使用的灵活性。在dependencyManagement元素下的依赖声明不会引入实际的依赖,不过它能够约束dependencies下的依赖使用。

    	<properties>
        	<java.version>1.8</java.version>
            <mirana.parent.version>1.0.0-SNAPSHOT</mirana.parent.version>
            <mirana.api.version>1.0.0-SNAPSHOT</mirana.api.version>
            <fastjson.version>1.2.76</fastjson.version>
            <guava.version>28.2-android</guava.version>
            <mapstruct.version>1.4.2.Final</mapstruct.version>
        </properties>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>com.ssozh</groupId>
                    <artifactId>mirana-api</artifactId>
                    <version>${mirana.api.version}</version>
                </dependency>
                <dependency>
                    <groupId>com.ssozh</groupId>
                    <artifactId>mirana-starter</artifactId>
                    <version>${mirana.parent.version}</version>
                </dependency>
                <!-- ................. -->
            </dependencies>
    </dependencyManagement>
    
    

    这样在实际test中使用的时候,直接省略了相关的versionscope信息。这些信息可以省略是因为子项目继承了父项目中的dependencyManagement配置。 这样虽然不能减少太多的POM配置,但是在父POM中声明是能够规范统一项目依赖的版本,子模块在使用依赖的时候就无须声明版本,也就不会发生多个子模块使用依赖版本不一致的情况,从而降低依赖冲突的几率。

    另外,对于前面介绍的import的依赖范围。使用该范围的依赖通常指向一个POM,作用是将目标POM中的dependencyManagement配置导入并合并到当前POM的dependencyManagement元素中。如果想要在另外一个模块中使用与某个模块玩去哪一样的dependencyManagement配置,除了复制配置或者继承这两种方式外,还可以使用import范围依赖将这一配置导入。

    8.3.2 插件管理

    Maven提供了dependencyManagement元素帮助管理依赖,Maven也提供了pluginManagement元素帮助管理插件。在该元素中配置的依赖不会造成实际的插件调用行为,当POM中配置了真正的plugin元素,并且GAV与pluginManagement中配置的插件匹配时,pluginManagement的配置才会影响实际的插件行为。

    例如父项目中可以这么写:

        <build>
            <pluginManagement>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-source-plugin</artifactId>
                        <version>3.2.1</version>
                    </plugin>
                </plugins>
            </pluginManagement>
        </build>
    

    8.4 聚合与继承的关系

    多模块Maven项目中的聚合与继承其实是两个概念,其目的是完全不同的。

    聚合 继承
    概念和目的 为了方便快速构建项目 为了消除重复配置
    使用方法 <modules>来聚合项目 子项目<parent><relativePath>。父项目的<xxxManagement>

    现有的实际项目中,往往一个POM既是聚合POM,又是父POM,这么做主要是为了方便。

    8.5 约定优于配置

    Maven会假设用户的项目是这样的:

    • 源码目录为src/main/java/
    • 编译输出目录为target/classes
    • 打包方式为jar
    • 包输出目录为target/

    遵循约定虽然损失了一定的灵活性,用户不能随意安排目录结构。如果想要修改 也可以在<build>中进行修改:

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

    实际上,任何一个Maven项目都是继承的超级POM。这点有点类似于任何一个java类都是隐式继承于Object类一样。在maven3中位置位于$MAVEN_HOMEmaven-model-buildersrcmain esourcesorgapachemavenmodelpom-4.0.0.xml

    具体看相关的代码:

     <build>
        <directory>${project.basedir}/target</directory>
        <outputDirectory>${project.build.directory}/classes</outputDirectory>
        <finalName>${project.artifactId}-${project.version}</finalName>
        <testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
        <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
        <scriptSourceDirectory>${project.basedir}/src/main/scripts</scriptSourceDirectory>
        <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
        <resources>
          <resource>
            <directory>${project.basedir}/src/main/resources</directory>
          </resource>
        </resources>
        <testResources>
          <testResource>
            <directory>${project.basedir}/src/test/resources</directory>
          </testResource>
        </testResources>
        <pluginManagement>
          <!-- NOTE: These plugins will be removed from future versions of the super POM -->
          <!-- They are kept for the moment as they are very unlikely to conflict with lifecycle mappings (MNG-4453) -->
          <plugins>
            <plugin>
              <artifactId>maven-antrun-plugin</artifactId>
              <version>1.3</version>
            </plugin>
            <plugin>
              <artifactId>maven-assembly-plugin</artifactId>
              <version>2.2-beta-5</version>
            </plugin>
            <plugin>
              <artifactId>maven-dependency-plugin</artifactId>
              <version>2.8</version>
            </plugin>
            <plugin>
              <artifactId>maven-release-plugin</artifactId>
              <version>2.5.3</version>
            </plugin>
          </plugins>
        </pluginManagement>
      </build>
    

    8.6 反应堆

    在一个多模块的Maven项目中,反应堆(reactor)是指所有组成的一个构建结构。对于单模块的项目,反应堆就是该模块本身,对于多模块而言,反应堆就包含了各模块之间继承与依赖的关系,从而计自动计算出合理的模块构建顺序。

    8.6.1 反应堆的构建顺序

    模块间的依赖关系会将反应堆构建成一个有向非循环图(directed acyclic graph,DAG)各个模块是该图的节点,依赖关系构成了有向边。这个图不允许出现循环,因此,当出现模块A依赖模块B,而B又依赖A的情况时,Maven就会报错。

    8.6.2 裁剪反应堆

    有些时候,用户会想要仅仅构建完整反应堆中的某些模块,换句话说,用户需要实时地裁剪反应堆。

    maven提供很多的命令行选择支持裁剪反应堆,输出mvn -h 可以看到这些选项:

    • -am:--also-make通收件所列模块的依赖模块
    • -amd:--alse-make-dependents同时构建依赖于所列模块的模块
    • -pl:--projects<args>构建指定的模块,模块间用逗号分隔
    • -rf:-resume-from <args>从指定的模块回复反应堆

    具体例子:

    # 构建完整反应堆
    mvn clean install
    # 使用-pl选项指定构建某几个模块
    mvn clean install -pl mirana-dal, mirana-biz
    ## 使用-am选项考研同时构建所列模块的依赖模块
    mvn clean install -pl mirana-dal -am
    ## 使用-amd选项考研同时构建依赖于所列模块的模块
    mvn clean install -pl mirana-dal -amd
    ## 使用—rf选项可以在完整的反应堆顺序基础上指定从哪个模块开始构建。例如:
    mvn clean install -rf mirana-dal
    

    在开发过程中,灵活应用上述4个参数,可以帮助我们跳过无需构建的模块,从而加速构建。【目前】我们的实际项目中没有用过这些

    8.7 小结

    本章介绍了聚合和继承两个特性,然后介绍了优化大于配置,最后介绍了反应堆 和相关的命令参数用于裁剪反应堆。

    其他

    1. junit注解

      1. @Before可以用在执行测试用例之前,执行该方法。可以用来初始化springframework的IoC容器。
      2. @Test注解标注的就是要测试的方法。
    2. 关于Maven中Model.class是如何通过maven-model中的maven.mdo生成的?

    3. 既然Maven不允许循环依赖,spring中通过@Resource的循环依赖是什么样的呢?

  • 相关阅读:
    打造一款便携版的Sublime Text
    git stash命令使用手册
    Java List 转 String
    myeclipse中java文件头注释格式设置
    IntelliJ IDEA详细配置和使用教程-字体、编码和基本设置
    Android Studio添加文件注释头模板?
    Windows + Ubuntu下JDK与adb/android环境变量配置完整教程
    android studio gradle dependencies 包存放在哪儿?
    用Gradle命令行编译Android工程
    十分钟玩转 jQuery、实例大全
  • 原文地址:https://www.cnblogs.com/SsoZhNO-1/p/15516559.html
Copyright © 2011-2022 走看看