maven依赖优化方案

2,417 阅读2分钟

  # 分享作者


昵称: arige

一、背景

image.png 1、整体项目架构如上图。所有的服务层包都会依赖基础设施中的所有的模块

2、不同的业务要依赖不同的服务层

3、用户可能会使用业务层中的一个或者多个业务模块

二、目标

通过对maven的优化,开发者接入的时候可以直接依赖需要的业务层包,而我们通过优化帮助开发者自动引入需要的服务层包和基础设施包

三、要解决的问题

1、明确各个业务层需要依赖的包,哪些是需要给开发者的,确保开发者集成了业务层包之后,能够自动引入业务层依赖的包

2、哪些是我们自己开发过程中需要,但是为了避免和开发者的冲突,而不带进去的,如何移除这些包?

四、实现原理

在Android项目中依赖maven仓库的时候,会有一个迭代遍历的过程

1、根据module中build.gradle的dependencies下的依赖项,按照在项目中build.gradle的repositories下的仓库路径和系统默认的路径去尝试下载

2、上一步的下载过程中会有一个pom文件的下载,这个是一个非常重要的文件,后续的所有操作都是对他的操作

3、在上一步的pom文件中会有一个非常重要的节点— dependencies 。如果该节点下有依赖项,会根据依赖性配置去下载对应的数据

五、具体实现

1、把依赖模块打入pom文件中

  <dependencies>
        <dependency>
            <!--依赖的group ID -->
            <groupId>org.apache.maven</groupId>
            <!--依赖的artifact ID -->
            <artifactId>maven-artifact</artifactId>
            <!--依赖的版本号。 在Maven 2里, 也可以配置成版本号的范围。 -->
            <version>3.8.1</version>
            <!-- 依赖类型,默认类型是jar。它通常表示依赖的文件的扩展名,但也有例外。一个类型可以被映射成另外一个扩展名或分类器。类型经常和使用的打包方式对应, 
                尽管这也有例外。一些类型的例子:jar,war,ejb-client和test-jar。如果设置extensions为 true,就可以在 plugin里定义新的类型。所以前面的类型的例子不完整。 -->
            <type>jar</type>
            <!-- 依赖的分类器。分类器可以区分属于同一个POM,但不同构建方式的构件。分类器名被附加到文件名的版本号后面。例如,如果你想要构建两个单独的构件成 
                JAR,一个使用Java 1.4编译器,另一个使用Java 6编译器,你就可以使用分类器来生成两个单独的JAR构件。 -->
            <classifier></classifier>
            <!--依赖范围。在项目发布过程中,帮助决定哪些构件被包括进来。欲知详情请参考依赖机制。 - compile :默认范围,用于编译 - provided:类似于编译,但支持你期待jdk或者容器提供,类似于classpath 
                - runtime: 在执行时需要使用 - test: 用于test任务时使用 - system: 需要外在提供相应的元素。通过systemPath来取得 
                - systemPath: 仅用于范围为system。提供相应的路径 - optional: 当项目自身被依赖时,标注依赖是否传递。用于连续依赖时使用 -->
            <scope>test</scope>
            <!--仅供system范围使用。注意,不鼓励使用这个元素,并且在新的版本中该元素可能被覆盖掉。该元素为依赖规定了文件系统上的路径。需要绝对路径而不是相对路径。推荐使用属性匹配绝对路径,例如${java.home}。 -->
            <systemPath></systemPath>
            <!--当计算传递依赖时, 从依赖构件列表里,列出被排除的依赖构件集。即告诉maven你只依赖指定的项目,不依赖项目的依赖。此元素主要用于解决版本冲突问题 -->
            <exclusions>
                <exclusion>
                    <artifactId>spring-core</artifactId>
                    <groupId>org.springframework</groupId>
                </exclusion>
            </exclusions>
            <!--可选依赖,如果你在项目B中把C依赖声明为可选,你就需要在依赖于B的项目(例如项目A)中显式的引用对C的依赖。可选依赖阻断依赖的传递性。 -->
            <optional>true</optional>
        </dependency>
    </dependencies>

其中和我们这次密切相关的是 **scope ** 节点

scope取值有效范围(compile, runtime, test)依赖传递
compileall
providedcompile, test
runtimeruntime, test
testtest
systemcompile, test

按照业务需求我们的包需要满足开发者在各个场景下的使用,那么我们就需要将我们的scope的值设置为compile,那对应的我们的build.gradle要怎么设置呢?

implementation 表示依赖,即 只依赖不打包进来。
api 表示打包,即 不仅依赖还打包进来,这样上层就不用重复依赖。

所以,我们要在打包的时候,将要提供出去的依赖,使用api来完成依赖

2、将在本地运行时需要,但是不需要提供开发者的包移除。

在gradle打包的过程中,publications 插件中,有一个功能,可以移除对应的依赖包

image_1.png

红框部分是真正的移除依赖的部分,我们可以按照业务需求,对这部分代码进行修改

六、结尾

至此整个修改完成

总结来说,就是将项目的依赖给进行处理,明确哪些是需要传递的,哪些是需要在真正打包的时候移除的。