maven - 用于接口和实现Spring的独立模块

2022-09-01 17:52:14

我们正在努力对Java项目进行Mavenization,我们希望在每个模块的接口和实现之间建立清晰的分离。为此,我们希望将每个模块拆分为两个子模块,一个用于它们使用的接口和数据对象,另一个用于实现。例如:

 +commons 
  +commons-api 
  +commons-impl 

模块的 POM 将配置为没有模块依赖于 impl 子模块。这样,来自一个模块的代码将无法“看到”另一个模块的实现细节。

我们遇到的问题是,将我们的弹簧XML放在哪里。在我们的项目中,我们使用通配符导入自动导入spring XML文件,例如

<import resource="classpath*:**/*-beans.xml"/>

这样,Spring XML的位置在运行时并不重要,因为所有模块都加载到同一个类加载器中,并且POV中严格的单向依赖规则不适用。

但是,在开发过程中,我们希望IDE(我们使用Intellij IDEA)来识别从弹簧XL引用的实现类。我们还希望IDEA能够识别其他模块中定义的bean。

如果我们把弹簧XML放在API子模块中 - 它们不会“看到”impl子模块中的实现类。如果我们将它们放在 impl 子模块中,它们的 bean 将不会从其他模块中“看到”。可能可以将IDEA项目配置为从没有依赖关系的模块中识别弹簧XL,但是我们更喜欢我们的POM来保存所有项目结构信息,而不是依赖IDEA项目文件。

我们考虑创建第三个子模块来保存Spring XML(可能还有休眠xml)。例如:

 +commons 
  +commons-api 
  +commons-impl 
  +commons-config

外部模块将同时依赖于 commons-apicommons-configcommons-config 将同时依赖于 commons-apicommons-impl,对 commons-impl 的依赖性标记为“提供”(以防止传递解析)。

然而,这似乎是一个复杂而尴尬的解决方案,我们认为必须有一种更好 - 更简单的方法来实现Maven和Spring的界面/impl分离。


答案 1

您需要的是运行时依赖范围:

运行时 - 此作用域指示依赖项不是编译所必需的,而是执行所必需的。它位于运行时和测试类路径中,但不在编译类路径中。

(https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html)

定义从一个 impl 模块到另一个 impl 模块的运行时依赖关系,您可以在其中使用 *-beans.xml 配置中的 impl 类。Intellij将在spring配置文件中正确识别这一点,但不会在代码中自动完成它们(但它会在测试代码中执行此操作)。

此外,如果有人在代码中使用了这些类,则通过 maven 进行编译将失败,因为运行时依赖项不在编译类路径上。


答案 2

您可以实现 api 和 impl 的解耦,如下所示:

+ commons (pom)
  + pom.xml         <--- serves as a parent aggregator (see below)
  + commons-api (jar)  <--- contains models, interfaces and abstract classes only
  + commons-impl (jar)  <--- depends on commons-api
  + commons-config (jar) <--- depends on commons-impl only (no need to depend on commons-api as it is brought in transitively)

 + external-project (war or jar) <--- has commons-config as a dependency

父聚合器 pom(指定构建顺序):

<modules>
  <module>commons-api</module>
  <module>commons-impl</module>
  <module>commons-config</module>
</modules>

如果配置模块仅包含 spring 应用程序上下文配置,则可以省略该模块。应用配置 xml 应位于包含要部署的项目的模块的类路径和文件夹结构中。因此,如果你正在构建一个战争工件,则应用上下文应该在那里。

应该在共享资源模块中的唯一配置是在 impl 模块的测试包中。


推荐