您如何处理仅在运行时才知道的传递依赖冲突?[关闭]


9

您通常如何处理大型软件项目在运行时发生的传递依赖问题?

在过去的三个星期中,我一直试图在一个软件的另一个组件中启动一个大型软件的一个组件,但是由于仅在运行时才知道的传递依赖项问题,该软件间歇性地消失了。

通过传递依赖关系问题,我的意思是给定项目的依赖关系的某些依赖关系在运行时与其他依赖关系发生冲突,从而导致不稳定或即时失败。

有成百上千的依赖在使用中,并且与该工具相关联的子项目大约有50个,这些其他项目是由其他团队隔离进行的,其中所有模块之间都具有深层嵌套的依赖关系。鉴于项目的规模和复杂性,没人知道所有子项目的用途。

在这种情况下,您是否会尝试为受影响的组件的每个依赖项生成DAG的可视化表示,并尝试确定在运行时可能在何处发生冲突?我无法控制其他子项目中依赖项的管理方式,也无法更改其他开发人员编写的任何Java代码

我提出的解决方案只能工作一两个小时,然后由于上游组件的更改而停止工作。上游组件的一个示例是工件,我正在处理的项目依赖于工件,该工件是在CI管道的较早阶段构建的。


应他人的要求,我将提供有关正在使用哪种技术的信息,可能会因提供太多信息而导致问题被解决,或者身体变得太长的风险:

  • Maven用于依赖性管理;和
  • Spring用作DI容器;
  • 由于在运行时加载了其他模块的上下文,因此大多数依赖性问题都涉及到重叠的Bean上下文。
  • 该产品运行正常,并且存在大量的单元测试和集成测试,以确保程序的功能正确性

总的来说,我正在寻找一种与语言无关的方法来确定解决依赖冲突的方法,而不用枚举给定项目依赖的所有可能组合。

我无法重新设计项目,添加其他质量保证,无法推动公司范围内的范式转换或切换语言作为解决方案。


您是否在谈论类似DI容器的设置不正确的问题,以至于对于IFoo而言,请使用IFooImpl?
安迪

不,它更像项目(b)中的程序包(b)是项目(A)中程序包(a)的传递依赖项,而(B)仅在运行时引入。我所能说的全部是软件,但我只需要适当的一组依赖关系就可以正确解决所有传递依赖关系。有一些依赖项可以使产品正常启动,但是,这些配置非常脆弱。作为初级开发人员。我对此无能为力。
泰勒(Tyler)2015年

2
拜托,“依赖关系问题”是一个非常笼统的术语,每个读过它的人都可能会想到不同的东西。对于现实世界而言,这是技术的依赖,因此请为您想到的特定技术提供一个真实的示例。是否由于缺少所需组件而引起问题?还是因为提供了错误的版本?哪种依赖关系解决机制已经到位?请说清楚。
布朗

1
在.Net世界中,我只需将软件包安装到主应用程序项目中即可解决此问题。尽管没有应用程序代码实际直接使用插件库,但.Net编译器可确保DLL在构建和部署期间位于正确的位置。
安迪2015年

2
“我无法控制依赖项的管理方式,并且无法更改任何代码”- 您实际上可以更改什么?如果您无法进行任何更改,那么这个问题似乎毫无意义。
布朗

Answers:


6

使用自定义类加载器为应用程序中的每个模块提供自己的执行环境,可能可以解决您的问题。

基本上,您将定义一个核心环境,其中包括应用程序的一个小内核,以及普遍同意的所有依存关系以及模块相互通信所需的所有接口。然后,您加载的每个模块都有自己的类加载器,该类加载器可以访问(1)运行时环境中的类,(2)应用程序核心中的类以及(3)该模块及其直接依赖关系中的类。所有模块间通信都通过内核中定义的接口进行,因此没有模块直接依赖于另一个模块。

此技术用于应用程序服务器中,以允许应用程序具有可能会冲突的依赖关系,因此您可以看到该技术的有效实现,例如在Tomcat中(如果幸运的话,您可以使用Tomcat的实施时几乎没有变化)。


1
我不允许重新设计项目以解决依赖关系问题。不过,切换到类似微内核的架构会很酷。
泰勒(Tyler)

2
@Tyler:尽管如此,我认为这是对问题的一般部分的一个很好的,一般的答案。
布朗

1
听起来有点像osgi。
SpaceTrucker

4

我从未与Maven或Spring一起工作过,但为您提供了一个通用问题的通用答案:涉及到依赖关系问题时,您的系统应设计为在最早的时间点以及何时发现这些问题时进行检测。 ,应立即发出信号,包括可能的原因。

理想情况下,该时间点不在“生产运行时”。最佳时间点是“构建时间”,但是对于您而言,这似乎是不可能的。因此,第二好的选择是运行时测试。您告诉我们有“集成测试”,但是由于它们没有检测到依赖关系问题,因此它们似乎不完整,或者通常不测试依赖关系冲突。那是您应该开始尝试解决问题的地方。

此外,为了使测试更有效,当出现依赖性问题时,您的组件需要“快速失败”。这意味着,一旦解决了依赖性并加载了组件,就应检查潜在的依赖性冲突并立即发出信号。如果系统在检测到碰撞之前先运行了一个小时,那么很难找出问题的原因。我不知道Maven / Spring是否已经为您提供了一种内置的“快速失败”策略,但是如果不是这样,请尝试朝这个方向思考。

为了减轻生产中的问题,应将系统设计为在发生涉及较不重要的子组件的依赖项冲突时不会完全消失。当然,不应掩盖故障,但理想情况下,系统应拒绝该组件的加载,记录和/或发出问题信号并保持稳定状态。第一次加载组件时,系统变得不稳定,然后才检测到问题,那么您可能将不得不完全关闭并重新启动系统,我想最好避免这种情况。

例如,如果您的系统是一个Web商店,并且您的“新闻通讯订阅”子模块无法加载几个小时,那么这似乎更容易容忍,好像整个商店都不再工作了。

最后,在您的情况下,这可能不是一个选择,但是如果可以使组件之间更好地隔离运行,并且如果可以避免依赖冲突,那么这可能是值得考虑的方法。


2

考虑一下,我只是在这里大声思考。根据需求/时间限制,我可能会考虑以下几点:

1)创建接口及其实现的列表(使用反射,如果可用)

2)在您的DI周围创建一种包装器。当要求DI提供具体的实现时,请查看是否已有DI规则;如果规则存在-只需返回您DI提供的信息 否则,如果只有一个接口实现,并且您可以创建一个实例-日志并返回一个实例;否则记录并失败。

我猜,这取决于您希望获得的参与程度,但是最终您只想拥有所需内容的完整列表-此解决方案最终将生成该列表。

但是,可以说这是一项艰巨的工作,而且不可靠-如果您遇到一个奇怪的情况,需要在一次蓝月亮中有一定的依赖性,该怎么办?

您说“上游组件的变化”是什么意思?


抱歉,我不想提供太多的背景信息-当我描述操作环境时,问题通常会被否决,甚至被烧死。我将使用定义部分更新原始问题。
泰勒(Tyler)2015年

2

如果我正确地理解了您的问题,那么问题是您需要使用的代码对以Spring XML表示的模块具有运行时依赖性,但是没有告诉maven它们。因此,当您使用它们时,它们所需的东西(可传递依赖项)不在您的类路径上,并且它们没有执行应有的操作。

我猜想当您问您的同事“我如何使它工作?”时,他们说“很显然,您需要35个模块和版本的清单,您怎么可能不知道呢?”

大概在完成集成测试后,所需的模块就被声明为测试依赖项。因此,系统的解决方案是对集成测试pom进行检查,以确保它们仅声明为测试依赖项的第三方测试工具。这甚至可以由maven强制执行程序插件自动执行

显然您无法做到这一点,因此您可能会在这里找到最佳选择。


据我所知,这就是正在发生的事情。到目前为止,我正在处理30个依赖项,并通过调整作用域来消除冲突,但是,这里需要进行同行评审。
泰勒(Tyler)2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.