What's the purpose of 'uses' directive in Java 9?

Mordechai :

Java's ServiceLoader class is now officially baked into the Java language. Instead of looking for providers in META-INF/services you can now use the

provides <spiClass> with <providerClass>

What I fail to understand is, the use of uses in the service loading module declaration:

uses <spiClass>

Quoting from The State of the Module System

The module system could identify uses of services by scanning the class files in module artifacts for invocations of the ServiceLoader::load methods, but that would be both slow and unreliable. That a module uses a particular service is a fundamental aspect of that module’s definition, so for both efficiency and clarity we express that in the module’s declaration with a uses clause:

module java.sql {
   requires transitive java.logging;
   requires transitive java.xml;
   exports java.sql;
   exports javax.sql;
   exports javax.transaction.xa;
   uses java.sql.Driver;
}

Why is it fundamental for the module system to know uses of a particular service, especially how will this introduce efficiency? Aren't services loaded lazily? Why can't the service loader just look for providers on the fly?

Nicolai :

When the JVM launches, the module system resolves dependencies and builds the module graph. Only modules that make it into the graph are available at run time (even if others are observable). If modules are properly decoupled via services, there is a good chance, though, that the providing modules are not transitive dependencies of the initial module. So without further efforts, service provider modules would routinely not make it into the module graph and thus not be available at run time when a module tries to use a service.

In order for the java.sql module to make use of this driver [...] the module system must add the driver module to the module graph and resolve its dependencies [...].

So for services to properly work, provider modules must make it into the module graph even if they are not transitively required from the initial module. But how can the module system identify which modules are needed as service providers? All that use a provides clause? That would be a little too much. No, only providers of services that are actually needed should be resolved.

This makes it necessary to identify services uses. As others have pointed out, bytecode analysis is slow and unreliable, so a more explicit mechanism is needed to guarantee efficiency and correctness: uses clauses. Only with them can the module system reliably and efficiently make all service provider modules available.

If the application is a module, then its module declaration must have a uses directive that specifies the service; this helps to locate providers and ensure they will execute reliably.

You can observe this behavior if launching a service-based application with the flag --show-module-resolution:

root monitor
monitor requires monitor.observer
[...]
monitor binds monitor.observer.beta
monitor binds monitor.observer.alpha

The module monitor binds the modules monitor.observer.alpha and monitor.observer.beta even though it does not depend on either of them.

(Quotes are from The State of the Module System; emphasis mine.)

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=433950&siteId=1