Java 可选编译时依赖关系是如何工作的?

Java 可选编译时依赖关系是如何工作的?,java,maven,Java,Maven,在很长一段时间里,我认为在Java中,您要么有两种依赖关系之一: 所需的编译时依赖项(编译时始终需要依赖项) 可能是可选的运行时依赖项(可以是 在运行时解析) 最近,我发现编译依赖项也可以是可选的。例如,commons beanutils被列为JXPath的一部分 这怎么行?依赖关系真的可以在编译时使用,但仍然是完全可选的吗 编辑:我可能不清楚。我正在寻找一个在编译时使用依赖项同时又是完全可选的情况,或者解释为什么不可能使用这种依赖项。一个类可以编译到一个接口,但在编译期间不需要该接口的实现

在很长一段时间里,我认为在Java中,您要么有两种依赖关系之一:

  • 所需的编译时依赖项(编译时始终需要依赖项)
  • 可能是可选的运行时依赖项(可以是 在运行时解析)
最近,我发现编译依赖项也可以是可选的。例如,
commons beanutils
被列为
JXPath
的一部分

这怎么行?依赖关系真的可以在编译时使用,但仍然是完全可选的吗


编辑:我可能不清楚。我正在寻找一个在编译时使用依赖项同时又是完全可选的情况,或者解释为什么不可能使用这种依赖项。

一个类可以编译到一个接口,但在编译期间不需要该接口的实现。在运行时需要实现


例如commons logging、JPA、JDBC等框架,应用程序可以基于这些框架进行编译。在运行时,需要一个实现来执行代码。示例实现—公共Bean UTIL、Oracle精简驱动程序、Eclipse链接等。

您所描述的实际上是构建工具Maven的一个功能,而不是Java本身。 如果没有构建工具,只需使用“javac”,就需要指定代码中直接使用的所有类或接口。当然有动态类加载甚至运行时编译的选项,但这不是主题

在前面的回答中描述了一个在接口和实现上分离的用例,另一个流行的用例基于类路径扫描: 如果某个特定类存在于类路径中和/或具有特定注释,则将加载一个可选模块

这就是Spring引导模块的加载方式。

其中的一段引文非常清楚地描述了这一点:

当无法(无论出于何种原因)将项目拆分为子模块时,使用可选依赖项。其思想是,某些依赖项仅用于项目中的某些功能,如果不使用该功能,则不需要这些依赖项。理想情况下,这样一个特性将被拆分为一个子模块,该子模块取决于核心功能项目。这个新的子项目将只有非可选的依赖项,因为如果您决定使用子项目的功能,您将需要所有这些依赖项

但是,由于项目无法拆分(同样,无论出于何种原因),这些依赖项被声明为可选的。如果用户想要使用与可选依赖项相关的功能,他们必须在自己的项目中重新声明该可选依赖项。这不是处理这种情况的最清晰的方法,但可选依赖项和依赖项排除都是权宜之计

为什么使用可选依赖项? 可选的依赖项可以节省空间和内存。它们可以防止违反许可协议或导致类路径问题的问题jar被捆绑到WAR、EAR、fat jar等中

可选依赖项是如何工作的? 上图显示Project-A依赖于Project-B。当A在其POM中将B声明为可选依赖项时,此关系保持不变。这就像一个普通的构建,Project-B将被添加到Project-a的类路径中

Project-X -> Project-A
当另一个项目(project-X)在其POM中将project-A声明为依赖项时,依赖项的可选性质将生效。Project-B不包含在Project-X的类路径中。您需要在Project X的POM中直接声明它,以便将B包含在X的类路径中

Project-X -> Project-A
一个实际的例子:假设您是一个库/框架
SuperLib
的开发人员,该库/框架构建为一个
SuperLib.jar
。您的库提供了多种功能。它的主要特性(大多数用户使用)是基于第三方
di
库的依赖注入。但是,您的一个类——
EmailApi
——提供了使用第三方
email
库发送电子邮件的功能。由于
superlib
是一个工件,因此需要编译
di
email

现在,将自己置于使用
superlib
的用户的位置。他们对依赖注入特性感兴趣。这是库的核心角色,因此
superlib
di
之间的依赖关系不是可选的

但是,大多数用户对发送电子邮件不感兴趣,可能会因为在应用程序中添加了无用的
电子邮件
库及其依赖项而感到烦恼(这将导致其应用程序的大小增加,并可能导致
电子邮件的依赖项和用户应用程序的依赖项之间的依赖项版本冲突)。因此,您会将
电子邮件
上的依赖项标记为
可选
。只要用户不使用
EmailApi
类,一切都会正常运行。但是,如果用户确实使用
EmailApi
,他们将需要
电子邮件
依赖项,否则应用程序将在运行时使用ClassNotFoundExc失败
EmailApi
中引用的
email
中的任何类的eption。您库的用户需要在其POM中明确添加
email
依赖项


另请参见。

类可以编译为接口,但在编译期间不需要该接口的实现。该实现在运行时是必需的。因此,编译时需要该实现,但在运行时是可选的?它是一个框架,具有编译期间需要的接口,在r期间需要实现如果在编译过程中需要带接口的框架,那么它不是可选的。我的问题是关于编译过程中使用的框架,但仍然是100%可选的。Jxpath依赖于常见的beanutils