我了解运行时和编译时之间的区别,以及如何区分两者,但我只是看不到需要区分编译时和运行时依赖项。
通用的编译时和运行时概念以及Maven特定compile
和runtime
作用域依赖性是两件截然不同的东西。您不能直接比较它们,因为它们没有相同的框架:一般的编译和运行时概念很宽泛,而Maven compile
和runtime
范围的概念则是根据时间(编译或执行)专门确定依赖项的可用性/可见性。
别忘了Maven首先是javac
/ java
包装器,在Java中,您有一个指定的编译时类路径javac -cp ...
和一个您指定的运行时类路径java -cp ...
。
将Maven compile
范围视为在Java编译和运行时classppath中添加依赖项的一种方式是正确的(javac
和java
),而Maven runtime
范围可以看作是仅在Java运行时classppath(javac
)中添加依赖项的一种方式。
我正在cho的是:程序如何在运行时不依赖于编译期间依赖的东西?
您描述的内容runtime
与compile
范围没有任何关系。您指定
的provided
范围看起来更像是一个依赖关系,该依赖关系在编译时而不是在运行时依赖于此。
您可以在需要依赖项进行编译时使用它,但是您不想将其包含在打包的组件(JAR,WAR或任何其他组件)中,因为环境已经提供了依赖项:它可以包含在服务器中或任何其他文件中指定为Java应用程序的类路径的路径已启动。
如果我的Java应用程序使用log4j,则它需要log4j.jar文件以便进行编译(我的代码与log4j集成并从其中调用成员方法)以及运行时(我的代码绝对无法控制log4j内的代码一旦发生了什么.jar已运行)。
在这种情况下,是的。但是,假设您需要编写一个依赖slf4j的可移植代码,将其作为log4j前面的外观,以便以后可以切换到另一个日志记录实现(log4J 2,logback或其他任何方法)。
在这种情况下,您需要将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一起使用。