我了解运行时和编译时之间的区别以及如何区分两者,但我只是不认为需要区分编译时和运行时依赖项。
一般的编译时和运行时概念以及 Maven 特定compile和runtime范围依赖是两个非常不同的东西。您不能直接比较它们,因为它们没有相同的框架:一般的编译和运行时概念是广泛的,而 mavencompile和runtime作用域的概念具体是关于根据时间的依赖关系可用性/可见性:编译或执行。
不要忘记 Maven 首先是一个javac/java包装器,而在 Java 中,您有一个用 指定的编译时类路径javac -cp ... 和一个用 指定的运行时类路径java -cp ...。
将 Mavencompile范围视为在 Java 编译和运行时 classppath 中添加依赖项的一种方式并没有错(javac和java),而 Mavenruntime作用域可以看作是一种仅在 Java 运行时 classppath ( javac) 中添加依赖项的方法。
我哽咽的是:程序如何在运行时不依赖它在编译期间依赖的东西?
runtime您所描述的与范围没有任何关系compile。对于您为依赖项指定
的范围而言,它看起来更像是在编译时而不是在运行时依赖于该范围。
您使用它是因为您需要编译依赖项,但您不想将其包含在打包的组件(JAR、WAR 或任何其他组件)中,因为该依赖项已经由环境提供:它可以包含在服务器或任何启动指定为 Java 应用程序的类路径的路径。 provided
如果我的 Java 应用程序使用 log4j,那么它需要 log4j.jar 文件才能编译(我的代码与 log4j 内部的成员方法集成并调用成员方法)以及运行时(我的代码完全无法控制 log4j 内部的代码会发生什么.jar 运行)。
在这种情况下是的。但是假设您需要在 log4j 前面编写一个依赖 slf4j 作为外观的可移植代码,以便以后能够切换到另一个日志记录实现(log4J 2、logback 或任何其他)。
在这种情况下,在您的 pom 中,您需要将 slf4j 指定为compile依赖项(这是默认值),但您将 log4j 依赖项指定为runtime依赖项:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>...</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>...</version>
<scope>runtime</scope>
</dependency>
这样,log4j 类无法在编译代码中引用,但您仍然可以引用 slf4j 类。
如果您随compile时间指定了这两个依赖项,则没有什么会阻止您在编译代码中引用 log4j 类,并且您可能会与日志记录实现产生不良耦合:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>...</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>...</version>
</dependency>
作用域的一个常见用法runtime是 JDBC 依赖声明。要编写可移植代码,您不希望客户端代码可能引用特定 DBMS 依赖项的类(例如:PostgreSQL JDBC 依赖项),但您希望将其包含在应用程序中,因为在运行时需要这些类JDBC API 与这个 DBMS 一起工作。