我了解运行时和编译时的区别并且知道如何区分两者,但我认为没有必要区分编译时和运行时依赖关系。一般的编译时和运行时概念以及Maven特定的“compile”和“runtime”范围依赖是两个非常不同的东西。你不能直接进行比较,因为它们的框架不同:一般的编译和运行时概念是广泛的,而Maven“compile”和“runtime”范围概念是关于依赖项在编译或执行时的可用性/可见性。
不要忘记Maven首先是一个“javac”/“java”包装器,在Java中,您有一个编译时类路径,可以使用“javac -cp…”指定,并且有一个运行时类路径,可以使用“java -cp…”指定。
可以把Maven“compile”范围视为在Java编译和运行时类路径(“javac”和“java”)中同时添加依赖项的一种方式,而可以将Maven“runtime”范围视为仅在Java运行时类路径(“javac”)中添加依赖项的一种方式。
你所描述的与“runtime”和“compile”范围没有任何关系。
这更像是你为某个依赖项指定“provided”范围,以便在编译时依赖它但在运行时不依赖它。
你需要这样做是因为需要依赖项进行编译,但不想将其包含在打包的组件(JAR、WAR或其他任何内容)中,因为该依赖项已经被环境提供了:它可以包含在服务器中或在启动Java应用程序时指定的任何类路径中。
如果我的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配合工作。