问题

我理解运行时和编译时之间的区别以及如何区分这两者,但我只是没有看到需要区分编译时和runtime依赖项

我窒息的是:程序如何在运行时依赖于编译时依赖的东西?如果我的Java应用程序使用log4j,那么它需要log4j.jar文件才能编译(我的代码与log4j内部的成员方法集成并调用成员方法)以及运行时(我的代码完全无法控制log4j中的代码会发生什么.jar跑了)。

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

任何人都可以给出一个简单的,"国王的英语"式的解释,最好有一个实际的例子,即使像我这样的可怜的人也能理解?


#1 热门回答(57 赞)

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

但是,并非严格要求;例如,我们可以针对某个API进行编译,使其成为编译时依赖项,但是在运行时包含一个也包含API的实现。

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

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

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


#2 热门回答(20 赞)

每个Maven依赖项都有一个范围,用于定义依赖项可用的类路径。

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

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

最常见的范围-编译范围-表示你的项目在编译类路径,单元测试编译和执行类路径以及执行应用程序时的最终运行时类路径时可用。在Java EE Web应用程序中,这意味着将依赖关系复制到已部署的应用程序中。但是在.jar文件中,编译范围不包含依赖项。

运行时作用域表示你的项目可以在单元测试执行和运行时执行类路径上使用该依赖项,但与编译范围不同,编译应用程序时,它不可用.89380865或其单元测试.**运行时依赖项将复制到已部署的应用程序中,但在编译期间无法使用!**这有助于确保你不会错误地依赖于特定的库。 (参见例如:http://www.tugay.biz/2016/12/apache-commons-logging-log4j-maven.html)

最后,提供的范围表示应用程序执行的容器代表你提供依赖关系。在Java EE应用程序中,这意味着依赖关系已经在Servlet容器或应用程序服务器的类路径中,而且**不会复制到已部署的应用程序中。**这也意味着你需要此依赖项来编译项目。


#3 热门回答(9 赞)

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

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


原文链接