[英]maven - separate modules for interfaces and implementation with Spring
我们正在研究Mavenizing我们的java项目,我们希望在每个模块的接口和实现之间建立一个清晰的分离。 为了做到这一点,我们希望将每个模块分成两个子模块,一个用于它们使用的接口和数据对象,另一个用于实现。 例如:
+commons
+commons-api
+commons-impl
将配置模块的POM,使得没有模块依赖于impl子模块。 这样,来自一个模块的代码就无法“看到”另一个模块的实现细节。
我们遇到麻烦的是,将Spring XML放在哪里。 在我们的项目中,我们使用通配符导入自动导入spring XML文件
<import resource="classpath*:**/*-beans.xml"/>
这样,Spring XML的位置在运行时并不重要,因为所有模块都被加载到同一个类加载器中,并且POM中严格的单向依赖规则不适用。
但是,在开发过程中,我们希望IDE(我们使用Intellij IDEA)识别从spring XML引用的实现类。 我们还希望IDEA识别其他模块中定义的bean。
如果我们将spring XML放在API子模块中 - 它们将不会“看到”impl子模块中的实现类。 如果我们将它们放在impl子模块中,它们的bean将不会从其他模块中“看到”。 可能可以将IDEA项目配置为从没有依赖项的模块中识别spring XML,但我们更喜欢POM保存所有项目结构信息而不依赖于IDEA项目文件。
我们考虑创建第三个子模块只是为了保存Spring XML(也许还有hibernate xmls)。 例如:
+commons
+commons-api
+commons-impl
+commons-config
外部模块将依赖于commons-api和commons-config , commons-config将依赖于commons-api和commons-impl ,并且依赖于commons-impl标记为“提供”(以防止传递解析)。
然而,这似乎是一个复杂而笨拙的解决方案,我们认为必须有一个更好 - 更简单的方法来实现与Maven和Spring的接口/ impl分离。
您需要的是运行时依赖范围:
runtime - 此范围指示编译不需要依赖项,但是用于执行。 它位于运行时和测试类路径中,但不是编译类路径。
( https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html )
定义从一个impl模块到另一个impl模块的运行时依赖关系,您可以在其中使用* -beans.xml配置中的impl类。 Intellij会在spring配置文件中正确识别它,但不会在代码中自动完成它们(但它会在测试代码中完成)。
此外,如果有人在代码中使用这些类,则通过maven进行编译会失败,因为运行时依赖性不在编译类路径上。
你可以像这样实现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应位于包含要部署的工件的模块的类路径和文件夹结构中。 因此,如果您正在构建战争工件,应用程序上下文应该在那里。
应该在commons模块中的唯一配置是在impl模块的测试包中。
简而言之,您希望Idea覆盖maven依赖关系图,但避免将此配置保留在想法项目文件中?
一种选择是在maven配置文件中对实现依赖性进行分组。 默认情况下不会启用此配置文件,但您应该能够在想法下将其标记为活动状态。
想到两个想法:
provided
这样的实施方式将是已知的,而没有该API为部署的依赖性。 commons-impl在外部模块的运行时范围内
公共(pom dependencyManagement)=>
+ commons-api(编译)
+ commons-impl(编译)
+ commons-config(编译)
commons-impl(pom dependencies)=>
+ commons-api(编译)
+ commons-config(编译)
外部模块(pom依赖)=>
+ commons-impl( 运行时 )
+ commons-api(编译)
+ commons-config(编译)
保持模块数量尽可能少;
这加快了项目构建时间并简化了布局。
保持模块结构尽可能简单:单根+同一文件夹中的所有子模块,例如:
pom.xml commons-api/ commons-runtime/ module-a-api/ module-a-runtime/ ...
当模块数量非常高(> 50)时,这简化了项目的导航
仅在需要时为运行时模块提供运行时范围的依赖关系;
这可以保持您的架构清晰。 使用mocks而不是显式依赖于另一个运行时模块。
在api模块中保存api spring上下文,将公共bean定义为abstract bean + interface;
将您的实现上下文保留在运行时模块中,通过spring配置文件覆盖api bean(使用<beans profile =“default”)。
结果:简单,透明的布局和设计; 全力支持; 没有对运行时模块内部的显式依赖。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.