我什么时候需要具有运行时范围的 Maven 依赖项

2022-01-15 00:00:00 dependencies java jar maven

我正在尝试了解 Maven 中对 runtime 范围依赖项的具体需求.在哪种情况下我需要这个,compileprovided 范围都不会这样做?

I'm trying to understand the specific need for runtime scoped dependency in maven. In which situation I would need this, where neither compile or provided scope won't do?

例如,当我必须直接在代码中调用库 API(针对它进行编译)并将依赖项打包到工件或依赖项目工件中时,我会使用 compile 范围作为依赖项.

For example, I would use compile scope for dependency, when I have to call the library API directly in the code (compile against it) and package the dependency in the artifact or dependent project artifacts.

当我必须针对 API 进行编译时,我会使用 provided 范围,但不要打包它(除非它在运行时可用).

I would use provided scope when I have to compile against the API, but don't package it (rather except it to be available at runtime).

但我什么时候需要 runtime 范围?这是否适用于我不直接调用库 API(而是使用反射)但想将其打包到工件中的情况?为什么不直接使用 compile 范围?唯一的好处是更快的编译时间,还是 runtime 范围内的其他特殊功能无法通过 compile 范围实现或避免?

But when would I need runtime scope? Is this for situations, when I don't directly call the library API (rather use reflection), but want to package it inside the artifact? Why not just to use compile scope? Is the only benefit faster compile time, or is there something other special in runtime scope that couldn't be achieved or avoided with compile scope?

推荐答案

你可以用 runtime 范围做的所有事情也可以用默认范围来完成:compile.
那么为什么要使用 runtime?

All what you can do with the runtime scope can be also done with the default scope : compile.
So why use runtime?

因为在某些情况下,这非常有意义,并且可以使您的构建更加健壮.

一个典型的用例是确保客户端代码不使用特定的实现.

A typical use case is ensuring that the client code doesn't use a specific implementation.

假设您构建的应用程序依赖于打包为 Maven 依赖项 (my-service-api) 的 API,并且此 API 的实现被打包为另一个 Maven 依赖项 (my-service-impl).
假设现在您需要在构建的应用程序中提供运行时的实现但您不希望您的应用程序的客户端代码直接引用该实现.

Suppose you build an application relying on an API packaged as a Maven dependency (my-service-api) and the implementation of this API is packaged as another Maven dependency (my-service-impl).
Suppose now you need to provide the implementation at the runtime in the built application but you don't want that the client code of your application refers directly the implementation.

通过使用 my-service-implruntime 范围:

By using the runtime scope for my-service-impl:

<dependencies>
​  <dependency>
​      <groupId>my-group</groupId>
​      <artifactId>my-service-api</artifactId>
​  </dependency>
​  
​  <dependency>
​      <groupId>my-group</groupId>
​      <artifactId>my-service-impl</artifactId>
​      <scope>runtime</scope>
​  </dependency>
<dependencies>

由于编译器永远不会在类路径中存在依赖项,因此您无法在应用程序的客户端代码中创建与实现的任何耦合.
客户端代码只会看到依赖的API:

As the compiler will never have the dependency in the classpath, you cannot create any coupling with the implementation in the client code of your application.
Client code will only see the API of the dependency :

通过使用 my-service-implcompile 范围:

By using the compile scope for my-service-impl:

<dependencies>
​  <dependency>
​      <groupId>my-group</groupId>
​      <artifactId>my-service-api</artifactId>
​  </dependency>
​  
​  <dependency>
​      <groupId>my-group</groupId>
​      <artifactId>my-service-impl</artifactId>    ​  
​  </dependency>
<dependencies>

情况有所不同:您可能会错误地引用实现类,从而与实现产生不合需要的耦合.

Things are different : you could by mistake reference implementation classes and so create an undesirable coupling with the implementation.

支持 runtime 范围的已知用法是您必须处理特定 DBMS(Oracle、PostgreSQL 或其他)的 JDBC 依赖项.
要编写可移植代码,您不想让客户端代码引用此 JDBC 依赖项的类,但您希望将其包含在您的应用程序中,因为在运行时需要这些类以使 JDBC api 与此 DBMS 一起工作.

A known usage to favor runtime scope is as you have to cope with a JDBC dependency of a specific DBMS (Oracle, PostgreSQL or whatever).
To write portable code, you don't want to allow the client code to refer to classes of this JDBC dependency but you want all the same include it in your application as at runtime the classes are needed to make the JDBC api works with this DBMS.

相关文章