2013-02-13 69 views
21

我们正在开发Mavenizing我们的java项目,并且我们希望为每个模块在接口和实现之间设置一个干净的分隔。 为了做到这一点,我们希望将每个模块分成两个子模块,一个用于接口和数据对象,另一个用于实现。 例如:maven - 用于接口和用Spring实现的独立模块

+commons 
    +commons-api 
    +commons-impl 

的模块的多金属氧酸盐将被构造成使得没有模块依赖于IMPL子模块。这样,一个模块中的任何代码都不能“看到”另一个模块的实现细节。

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

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

这样春天个XML的位置并不重要,在运行时,所有的模块得到加载到相同的类加载器和,POM中严格的单向依赖关系规则不适用。

然而,在开发过程中,我们希望IDE - 我们使用IntelliJ IDEA的 - 承认从春天个XML引用的实现类。 我们也希望IDEA识别在其他模块中定义的bean。

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

我们考虑建立第三子模块刚刚举行春季个XML(或许冬眠个XML以及)。例如:

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

外部模块将取决于两个公地-API公地配置公地配置将取决于两个公地-API公地IMPL,依赖于commons-impl标记为“提供”(以防止传递性解析)。

然而,这似乎是一个复杂而尴尬的解决方案,我们觉得必须有一个更好 - 更简单的方式来实现与Maven和Spring接口/ IMPL分离。

+2

很好的问题,但没有答案呢?真是可惜.. – cirit 2015-07-15 12:18:04

+1

@cirit同意 - 开始赏金 – drewmoore 2015-10-01 12:06:56

回答

1

总之你想要理念覆盖Maven的依赖关系图,但要避免在保持想法的项目文件这个配置?

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

+0

我不想完全重写图表,我只想让Spring XML文件在Maven项目中可见,其中不存在依赖关系... – dkarlinsky 2013-02-14 15:27:59

1

两个想法浮现在脑海中:

  1. 你将有一个(或多个)模块,所有模块(API + implement执行)的依赖,也可以有把你的Spring配置文件。
  2. 将spring配置文件放在api模块中,并声明对范围为provided的impl模块的依赖关系,这样实现将是已知的,而api对于部署没有依赖性。
6

你需要的是一个运行时依赖范围:

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

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

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

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

1
  • 公地IMPL在运行范围

    1. 公地(POM dependencyManagement)=>

      +公地-API(编译)

      +公地IMPL(编译)

      + commons-config(编译)

    2. 公地IMPL(POM依赖性)=>

      +公地-API(编译)

      +公地配置(编译)

    3. 外部模块(POM依赖性)=>

      +公地IMPL(运行时

      +公地-API(编译)

      +公地配置(编译)

2

可以实现API和实现解耦是这样的:

+ 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> 

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

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

1
  1. 保持模块数量尽可能少;

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

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

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

这简化在整个项目中,当模块的数量是非常高(> 50)

  • 提供运行时范围的依赖关系到运行时的导航模块只有在需要时;

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

  • 在api模块中保留你的api spring上下文,将你的public bean定义为抽象bean +接口;

  • 在运行时模块中保留您的实现上下文,通过弹簧配置文件使用您的实现覆盖api bean(使用< beans profile =“default”)。

  • 结果:简单,透明的布局和设计;完整的IDE支持;在运行时模块内部没有明确的依赖关系。