我有这种依赖情况:
C( - >)B - > A - > ç
其中B-> C表示模块C在其pom.xml中与B有依赖关系。
嗯...我想在C中使用B中的一个类,所以我必须把C-> B,但是我收到一个循环错误,你可以看到上面...
你看到任何解决方法吗?我不能在C中用B移动那个类,因为它已经使用了A中的一些类,并且会再次循环。
我试图在C中声明一个接口IAlfa并在B(Alfa)中实现它(但是当我想使用它时,我需要实例化如下:
IAlfa alfa = new Alfa()
所以我再次需要从B中导入Alfa。
您怎么看?
感谢。
答案 0 :(得分:5)
这不应该发生。我通常做的是这样的模块结构:
root
- api (interfaces, enums and custom exceptions only)
- impl (standard implementation of api -> dependency to api)
- server (runtime dependency to impl, compile time to api only)
- client (dependency to api only)
假设我们在Person
模块中有一个接口api
。现在在impl
模块中,您有一个类JpaPerson
,因为impl
使用JPA。但是,这些是客户端和服务器现在不需要的详细信息,因此您不应(在我的设计中不能)在new JpaPerson()
或client
中执行server
。相反,你有一个名为api
的界面(也在PersonFactory
内)(当你谈论人时听起来很糟糕,或者说它更人性化),它有这样的方法:
public interface PersonFactory{
Person findPersonBySsn(String socialSecurityNumber);
List<Person> findPersonsByName(String firstName, String lastName);
List<Person> findPersonByBirthDate(Date birthDate);
Person createPerson(
String firstName, String lastName,
Date birthDate, String socialSecurityNumber
);
}
同样,在impl
模块中实现此接口,但仅在其他模块中将其作为接口引用。然后使用dependency injection将事物连接在一起(Spring,SEAM,EJB3,等等)。
您提到的情况是代码执行超出其职责范围的结果(请阅读separation of concerns)。
这种设计的最大优点是您可以单独重构所有模块(api
除外),而无需更改其他模块中的代码。因此,如果您想从jpa切换到经典休眠,只需编辑impl
即可。如果要将服务器从轴切换到cxf,只需更改server
即可。这使事情变得容易多了。当然,你没有获得循环依赖。
编辑:
一个简单(简单)的解决方案是引入一个模块d,它包含在a,b和c中作为依赖项。将所有常用代码移至d。 (实际上将此d重命名为a和a,b,c重命名为b,c,d)。
答案 1 :(得分:2)
这种情况似乎是阶级/图书馆组织不良的症状。
你会合理地进入这种情况似乎很奇怪(如果你想讨论那个,你可以更准确地解释你如何组织你的课程)
如果您完全掌控A,B和C的构成,您至少可以做以下事情:
答案 2 :(得分:1)
有几件事要做。
首先从工件C开始一直使用mvn dependency:analyze
来验证实际使用的依赖关系,而不只是在pom.xml
中声明,这个Maven插件非常有用,作为第一步到调试你的依赖树。情况可能是某些依赖项只是声明但未使用,和/或使用但未声明等。
一旦验证了依赖关系树的真实状态,那么你应该开始移动东西,以防你的依赖关系分析步骤没有显示任何可以轻松解决的重大问题。
我不知道您的问题有多深,因为您尚未发布任何配置和/或代码剪切,但您可以尝试使用C pom.xml
之类的内容:
<dependency>
<groupId>org.sample</groupId>
<artifactId>module-b</artifactId>
<exclusions>
<exclusion>
<groupId>org.sample</groupId>
<artifactId>module-c</artifactId>
</exclusion>
</exclusions>
</dependency>
从A的传递中继承C的依赖性。
答案 3 :(得分:0)
大多数情况下,当我必须解决这样的问题时,我在POM文件中显式声明了依赖项,然后向相关的依赖项添加了一个EXCLUDES子句。这样我肯定会得到我想要的版本。它的工作量更大,但它可以使您免于在WAR文件中记录12个公共空间副本。 ;)