当前位置:Java -> Maven 依赖范围应用

Maven 依赖范围应用

为了开始,我们将以一个典型的三层应用为例,分析模块边界和管理这些模块所面临的挑战。选择了这种特定的架构,假设这对每个人来说都很熟悉。这应该让我们专注于通过解决这些问题来关注Maven依赖管理

三层应用示例

此示例的源代码可以在以下链接找到。

三层应用示例

根据三层架构,目标是拥有保持相互隔离的层,仅通过附近层(模块)的APIs进行交互。

对于这种结构的典型Maven 模块配置可能如下所示。

<!--web module pom.xml -->
<dependencies>
  <dependency>
    <groupId>com.example</groupId>
    <artifactId>service</artifactId>
    <version>1.0.0</version>
  </dependency>  
</dependencies>

<!--service module pom.xml -->
<dependencies>
  <dependency>
    <groupId>com.example</groupId>
    <artifactId>dao</artifactId>
    <version>1.0.0</version>
  </dependency>
</dependencies>


我们目前的主要关注点是这种设置需要提供我们期望的模块封装级别。例如,仍然可以在serviceweb模块中使用dao模块中声明的任何公共类。随着应用程序的增长和演变,这可能会破坏最初的设计,导致一个耦合度极高的应用程序。

鉴于以上情况,让我们看看如何改进这个解决方案,通过对初始应用样本进行一些重构并更新它的pom.xml文件来更好地控制模块边界。

改进后的三层应用示例

此示例的源代码可以在以下链接找到。

改进后的三层应用示例

<!--web module pom.xml -->
<dependencies>
  <dependency>
    <groupId>com.example</groupId>
    <artifactId>service-api</artifactId>
    <version>1.0.0</version>
  </dependency>
  <dependency>
    <groupId>com.example</groupId>
    <artifactId>service</artifactId>
    <version>1.0.0</version>
    <scope>runtime</scope>
  </dependency> 
</dependencies>

<!--service module pom.xml -->
<dependencies>
  <dependency>
    <groupId>com.example</groupId>
    <artifactId>dao-api</artifactId>
    <version>1.0.0</version>
  </dependency>
  <dependency>
    <groupId>com.example</groupId>
    <artifactId>dao</artifactId>
    <version>1.0.0</version>
    <scope>runtime</scope>
  </dependency>
  <dependency>
    <groupId>com.example</groupId>
    <artifactId>service-api</artifactId>
    <version>1.0.0</version>
  </dependency>
</dependencies>

<!--dao module pom.xml -->
<dependencies>
  <dependency>
    <groupId>com.example</groupId>
    <artifactId>dao-api</artifactId>
    <version>1.0.0</version>
  </dependency>
</dependencies>


在这个改进版本中添加了两个新模块:dao-apiservice-api。此外,除了默认的编译范围外,现在有些依赖关系是运行时范围。根据Maven的依赖范围文档:

  • Compile: 默认范围,如果未指定范围,则使用此范围。编译依赖关系可在项目的所有类路径中使用。此外,这些依赖关系会传播到依赖项目。
  • Runtime: 这个范围表示该依赖关系不是编译所必需的,但是对执行是必需的。Maven将依赖关系与此范围包含在运行时和测试类路径中,但不包含在编译类路径中。

此配置的结果是只有来自dao-apiDAO接口service模块中可用,确保没有暴露dao内部。对于serviceweb模块之间的关系也是如此。

尽管添加新模块可能需要更多的工作,可能被视为额外的复杂性,但这是为了更好地封装而进行的合理折衷,这对于遵守所选择的设计是至关重要的。

结论

通过本文,我们揭示了在具有Maven的多模块项目中管理依赖关系的一种简单却经常被忽视的方法。尽管这可能需要相当多的工作,但其应用可以显著改善对模块边界的控制。尤其是在像Java平台模块系统ArchUnit这样的可能的替代方案出于某种原因不可行时。

推荐阅读: 阿里巴巴面经(56)

本文链接: Maven 依赖范围应用