26

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

 +commons 
  +commons-api 
  +commons-impl 

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

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

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

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

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

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

我们考虑创建第三个子模块来保存 Spring XML(也许还有 hibernate xml)。例如:

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

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

然而,这似乎是一个复杂而笨拙的解决方案,我们认为必须有一种更好、更简单的方法来实现与 Maven 和 Spring 的接口/实现分离。

4

6 回答 6

7

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

运行时- 此范围表示编译不需要依赖项,但需要执行。它在运行时和测试类路径中,但不在编译类路径中。

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

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

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

于 2015-10-01T15:44:36.640 回答
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>

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

应该在您的 commons 模块中的唯一配置将在您的 impl 模块的测试包中。

于 2015-10-03T05:43:44.160 回答
1

简而言之,您希望 Idea 覆盖 Maven 依赖关系图,但避免将此配置保留在 IDEA 项目文件中?

一种选择是在 Maven 配置文件中对实现依赖项进行分组。默认情况下不会启用此配置文件,但您应该能够将其标记为在想法下处于活动状态。

于 2013-02-13T15:28:32.380 回答
1
  1. 尽量减少模块数量;

    这加快了项目构建时间并简化了其布局。

  2. 保持模块结构尽可能简单:单个根 + 同一文件夹中的所有子模块,例如:

    pom.xml
    commons-api/
    commons-runtime/
    module-a-api/
    module-a-runtime/
    ... 
    

当模块数量非常高(> 50)时,这简化了整个项目的导航

  1. 仅在需要时向运行时模块提供运行时范围的依赖项;

    这使您的架构保持清晰。使用模拟而不是显式依赖另一个运行时模块。

  2. 将您的 api spring 上下文保存在 api 模块中,将您的公共 bean 定义为抽象 bean + 接口;

  3. 将您的实现上下文保存在运行时模块中,通过 spring 配置文件用您的实现覆盖 api bean(使用 <beans profile="default")。

结果:简单、透明的布局和设计;完整的IDE支持;对运行时模块内部没有显式依赖。

于 2015-10-05T23:04:32.927 回答
1
  • 外部模块中运行时范围内的 commons-impl

    1. 公地(pom 依赖管理)=>

      +commons-api (编译)

      +commons-impl (编译)

      +commons-config (编译)

    2. commons-impl(pom 依赖项)=>

      +commons-api (编译)

      +commons-config (编译)

    3. 外部模块(pom 依赖项)=>

      +commons-impl (运行时)

      +commons-api (编译)

      +commons-config (编译)

于 2015-10-02T11:43:38.507 回答
1

想到两个想法:

  1. 您将拥有一个(或多个)模块,其中所有模块(api+impl)都是依赖项,您可以将 spring 配置文件放在那里。
  2. 将 spring 配置文件放在 api 模块中,并声明对具有范围的 impl 模块的依赖关系,provided这样就可以知道实现,而部署时没有 api 依赖关系。
于 2015-10-01T09:32:46.573 回答