一个程序在编译期间是否依赖于库而不是运行时?

我理解运行时间和编译时间之间的区别,以及如何区分这两者,但我不认为需要区分编译时和运行时依赖

我ch咽的是这样的:一个程序如何不依赖运行时依赖于编译期间的东西? 如果我的Java应用程序使用log4j,那么它需要log4j.jar文件来编译(我的代码与log4j内部的成员方法集成和调用)以及运行时(我的代码完全不能控制一旦log4j内部的代码发生了什么.jar运行)。

我正在阅读像Ivy和Maven这样的依赖parsing工具,这些工具明确地区分了这两种依赖关系。 我只是不明白它的需要。

任何人都可以给出一个简单的“国王英语”式的解释,最好有一个像我这样的穷人可以理解的实际例子吗?

运行时通常需要编译时间依赖性。 在maven中, compile范围的依赖关系将被添加到运行时的类path中(例如在战争中它们将被复制到WEB-INF / lib中)。

但是,这并不是严格要求的。 比如,我们可以针对特定的API进行编译,使其成为编译时依赖,但是在运行时包含一个也包含API的实现。

在项目需要一定的依赖性编译的情况下,可能会出现这样的情况,但是实际上并不需要相应的代码,但这些情况很less见。

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

编译时依赖可以通过使用reflection来避免。 例如,一个JDBC驱动程序可以用一个Class.forName加载,而实际加载的类可以通过configuration文件进行configuration。

每个Maven依赖项都有一个作用域,用于定义哪个依赖关系可用的类path。

为项目创buildJAR时,依赖关系不会与生成的工件捆绑在一起; 它们只用于编译。 (但是,你仍然可以使Maven在构build的jar中包含依赖关系 ,参见: 在Maven的jar中包含依赖关系 )

使用Maven创buildWAR或EAR文件时,可以将Mavenconfiguration为将依赖项与生成的工件捆绑在一起,也可以使用提供的作用域将其configuration为从WAR文件中排除某些依赖项。

最常见的作用域 – 编译范围( Compile Scope) – 表示在执行应用程序时,依赖关系可用于编译类path上的项目,unit testing编译和执行类path以及最终的运行时类path。 在Java EE Web应用程序中,这意味着依赖项被复制到已部署的应用程序中。 然而,在.jar文件中,依赖关系不会被包含在编译范围中。

运行时作用域表明依赖关系可用于unit testing执行和运行时执行类path上的项目,但与编译范围不同的是,在编译应用程序或其unit testing时不可用运行时依赖关系被复制到已部署的应用程序中,但在编译期间不可用! 这对确保您不会错误地依赖特定的图书馆很有帮助。 (例如: http : //www.tugay.biz/2016/12/apache-commons-logging-log4j-maven.html )

最后,“已提供的范围”表示您的应用程序在其中执行的容器将以您的名义提供相关性。 在Java EE应用程序中,这意味着依赖关系已经存在于Servlet容器或应用程序服务器的类path中, 并且不会复制到已部署的应用程序中。 这也意味着你需要这个依赖来编译你的项目。

在编译时需要在运行时可能需要的依赖关系。 但是,许多库运行没有所有可能的依赖关系。 即一个库可以使用四个不同的XML库,但只需要一个工作。

许多图书馆依次需要其他图书馆。 这些库在编译时不需要,但在运行时需要。 即代码实际运行时。

一般而言,如果运行时和编译时间依赖性相同,则这是理想的情况。

当这个规则不正确时,我会给你2个例子。

如果A类依赖于依赖于类C的类B,而类C依赖于类D,其中A是你的类,而B,C和D是来自不同第三方库的类,那么在编译时你只需要B和C,运行。 程序经常使用dynamic类加载。 在这种情况下,您不需要在编译时使用库dynamic加载的类。 此外,库经常select在运行时使用哪个实现。 例如,SLF4J或Commons Logging可以在运行时更改目标日志实现。 在编译时你只需要SSL4J。

在编译时需要比运行时更多的依赖关系的例子就是相反的例子。 认为你正在开发必须在不同的环境或操作系统上工作的应用程序。 在编译时需要所有特定于平台的库,在运行时只需要当前环境所需的库。

我希望我的解释有帮助。

通常,静态依赖关系图是dynamic关系图的子图,参见例如NDepend作者的博客条目 。

也就是说,有一些例外,主要是增加了编译器支持的依赖,在运行时变得不可见。 例如,通过Lombok进行代码生成或者通过(可插入types)Checker框架进行额外的检查。

刚刚遇到一个问题,回答你的问题。 servlet-api.jar是我的web项目中的一个临时依赖项,在编译时和运行时都需要它。 但是servlet-api.jar也包含在我的Tomcat库中。

这里的解决scheme是使maven中的servlet-api.jar仅在编译时可用,而不是打包在我的war文件中,这样它就不会与我的Tomcat库中包含的servlet-api.jar冲突。

我希望这解释了编译时间和运行时依赖。

在编译时,您可以启用您的依赖关系所期望的契约/ API。 (例如:在这里,您只需签署与宽带互联网提供商的合同)在运行时,实际上您正在使用依赖关系。 (例如:在这里你实际上正在使用宽带互联网)