什么是管理项目依赖的最佳方法?

3

我在一个服务中有以下依赖关系层次结构:

Service A
   -> Lib A
   -> Lib B
      -> Lib A
   -> Lib C
      -> Lib A
    -> Lib D
      -> Lib A

"->"表示依赖于。

由于上述结构,出现了很多问题。其中需要投入大量精力的问题是保持Lib A在所有模块中同步以避免类冲突和其他问题

我使用maven进行依赖管理,但它并不能解决这个问题,因为我必须更新所有依赖项以避免冲突(语义和功能)。

有更好的方法来管理这些依赖关系吗?

编辑1:

场景1:向仅由Lib B使用的Lib A添加新代码。

在这种情况下,仅更改Lib B是不够的。我将不得不在service A中添加最新版本的Lib A,以便maven选择正确的版本。

场景2:A中不向后兼容的更改。

如果我只是在Service A中更新Lib A,那么其他库(B、C和D)可能就不知道这个新变化,这可能会导致问题(例如,在现有方法中添加一个新参数)。我将不得不更新所有这些库。

场景3:更改Lib A中的现有方法。

这将正常工作。如果我在service A中更新此Lib A,maven将挑选最新的Lib A,所有库(B、C和D)都将使用Lib A的最新版本。


尝试使用依赖分析器作为插件,它会在出现任何问题(如使用/未使用冲突等)时发出警告。 - Indra Uprade
在这种情况下,我知道依赖关系层次结构,并且我知道一旦我更改了Lib A,我将不得不更改(Service A、Lib B、Lib C和Lib D)。 - Atul
1
“将新代码添加到仅由Lib B使用的Lib A”意味着Lib A不仅是一个库,而是多个库。 您应该考虑将Lib A划分为多个较小的库,其中Lib A仅包含所有库共有的代码,然后将特定于Lib BLib CLib D的部分直接移动到那些库或移动到Lib BA, Lib CA, Lib DA等库中。 - manish
@manish 这并不完全正确。如果lib A是像log4j这样的库,而lib B恰好是唯一需要记录如此多日志以至于需要滚动日志文件的库,那么如果有关于滚动日志文件的更新,那么lib C和lib D肯定不会关心,但我不会认为滚动日志文件应该放在它们自己的库中。 - Pace
node 开发者经常这样做,而且效果非常好。这对于方案2尤其有利。我确实认为解决方案是在应用程序中有多个第三方库的版本,但我不认为这是糟糕的设计。我也没有主张以这种方式处理每个第三方库(例如 servlet API)。 - Pace
@Atul,从我对你的情况的理解来看,你负责Service A、Lib A、B、C和D的代码。如果确实是这样,并且作为开发人员,你知道必须修改Lib A,那么你应该更新所有依赖于Lib A的构件的依赖关系。如果没有方便的工具,发布流程可能会很繁琐,但你应该尽量避免维护库版本的兼容性表。话虽如此,如果问题变成了一个经常性的问题,那么你应该再次查看Pace的评论。 - Arthur Noseda
4个回答

1

在这种情况下,使用可选依赖项或排除它们都无法帮助。我已经添加了一些场景供您参考。 - Atul

0
你可以考虑使用OSGi或Java 9模块(当然还没有完成)。我不是专家,但我相信这些框架允许模块/包的概念,每个模块都有自己的类加载器。这意味着如果lib B和lib C是模块,则它们可以拥有不同版本的lib A,并且一切都可以顺利运行。它确实防止了lib B和lib C直接通信,但考虑到您的依赖树,这应该是期望的。
--更新以匹配您的更新--
情况1:
仅在模块B中更新lib A版本。模块C/D可以保持不变。
情况2:
当每个模块准备好使用新版本的lib A时,可以独立地在模块B/C/D中更新lib A。
情况3:
没有问题。

0

思考领域驱动设计,更具体地说是有界上下文模式。它允许在一定程度上进行代码复制。这种灵活性将允许您轻松地将“jar A”与其余部分解耦。

什么是有界上下文?

让我们想象我们有一个用户。在一个上下文中,这个用户可以是用户管理员,在另一个上下文中,它可以是高级用户,或者在另一个上下文中可以只是普通用户

现在让我们想象我们有3个服务,针对基于其类型的用户的三个不同功能。每个服务代表术语用户的不同上下文。现在,关键在于,我们将根据上下文创建3个用户,而不是在您的情况下将其全部放入万能的“libA”中,并为这3个用户提供不同的功能。最终,我们将得到3个领域对象:服务1的AdminUser,服务2的PowerUser和服务3的普通User。这三个服务将彼此没有依赖关系,除非符合我们的需求,即使它们存在依赖关系,也很容易在任何时候解耦它们。

如果我们开始将服务视为洋葱。在第一层,我们将拥有持久性。在第二层,我们将开始展开我们的领域模型。在下一层,我们将开始构建我们的服务。然后是我们的网络表示等等。

有界上下文的方式思考将允许您在每个服务基础上创建一个独特的有界上下文,这将使您不必在不同的Jars之间具有这些相互依赖关系。这是因为您的服务不一定与其他服务共享代码。


0
Service A
   -> Project Commons
       -> Lib B_A (functional dependency, commons B no functional dependency with C and D)
       -> Lib C_A (functional dependency, commons C no functional dependency with B and D)
       -> Lib D_A (functional dependency, commons C no functional dependency with B and C)
       -> Lib A (technical dependencies , commons in B C D)
       -> pom_parent
   -> Lib B
      -> Lib A and Lib B_A
   -> Lib C
      -> Lib A and Lib C_A
    -> Lib D
      -> Lib A and Lib D_A
pom_parent (SNAPSHOT)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接