程序是否可以在编译期间依赖于库,而不是运行时?

2022-08-31 08:55:07

我了解运行时和编译时之间的区别以及如何区分两者,但我只是不认为有必要区分编译时和运行时依赖关系

我呛到的是:一个程序怎么能不依赖于它在编译过程中所依赖的运行时的东西呢?如果我的Java应用程序使用log4j,那么它需要log4j.jar文件来编译(我的代码与log4j内部集成并从中调用成员方法)以及运行时(我的代码完全无法控制一旦运行log4j.jar中的代码会发生什么)。

我正在阅读依赖关系解决工具,如Ivy和Maven,这些工具清楚地区分了这两种类型的依赖关系。我只是不明白它的必要性。

谁能给出一个简单的,“国王的英语”类型的解释,最好是一个实际的例子,即使是像我这样的可怜的树液也能理解?


答案 1

在运行时通常需要编译时依赖项。在 maven 中,一个作用域依赖关系将在运行时添加到类路径中(例如,在战争中,它们将被复制到 WEB-INF/lib)。compile

然而,这并不是严格要求的。相反,它需要更多的资金。例如,我们可以针对某个API进行编译,使其成为编译时依赖项,但在运行时包括一个也包含API的实现。

可能存在一些边缘情况,即项目需要一定的依赖关系来编译,但实际上并不需要相应的代码,但这些情况很少见。

另一方面,包括编译时不需要的运行时依赖项是非常常见的。例如,如果您正在编写Java EE 6应用程序,则可以使用Java EE 6 API进行编译,但在运行时,可以使用任何Java EE容器;正是这个容器提供了实现。

通过使用反射,可以避免编译时依赖关系。例如,可以使用 Class.forName 加载 JDBC 驱动程序,并且可以通过配置文件配置加载的实际类。


答案 2

每个 Maven 依赖项都有一个作用域,用于定义该依赖项在其上可用的类路径。

为项目创建 JAR 时,依赖项不会与生成的工件捆绑在一起。它们仅用于编译。(但是,您仍然可以让 maven 在构建的 jar 中包含依赖项,请参阅:使用 Maven 在 jar 中包含依赖项)

使用 Maven 创建 WAR 或 EAR 文件时,可以将 Maven 配置为将依赖项与生成的工件捆绑在一起,还可以将其配置为使用作用域从 WAR 文件中排除某些依赖项。provided

最常见的作用域 — — 指示在执行应用程序时,项目在编译类路径、单元测试编译和执行类路径以及最终运行时类路径上的依赖项可用。在 Java EE Web 应用程序中,这意味着依赖项将复制到已部署的应用程序中。但是,在 JAR 文件中,使用作用域时将不包括依赖项。compilecompile

runtimescope 指示项目在单元测试执行和运行时执行类路径上可以使用依赖关系,但与作用域不同,在编译应用程序或其单元测试时,该依赖项不可用。运行时依赖项将复制到已部署的应用程序中,但在编译期间不可用。这有利于确保您不会错误地依赖于特定的库。假设您正在使用特定的日志记录实现,但您只想在源代码中导入日志记录外观。您将包含具有作用域的具体日志库,这样您就不会错误地依赖它。compileruntime

最后,scope 指示执行应用程序的容器代表您提供依赖项。在 Java EE 应用程序中,这意味着依赖项已经位于 Servlet 容器或应用程序服务器的类路径上,并且不会复制到已部署的应用程序中。这也意味着您需要此依赖项来编译项目。provided


推荐