Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 432
Mordechai Avatar asked Aug 20 '17 02:08

Mordechai


People also ask

What are the main goals of Java 9?

The main goals for Java 9 are to: Make the Java Standard Edition platform, and the JDK, more navigable to scale down for small computing devices. Improve the overall security and maintain not only the JDK but the Java Implementations in general. Allow overall improved application performance.

What is the use of module info Java?

module-info. java file. It declares the dependencies within the module system and allows the compiler and the runtime to police the boundaries/access violations between the modules in your application. Let's look at the file syntax and the keywords you can use.

What is a module system in Java 9?

Defining the Java 9 module. A module is a collection of code, data, and resources. It is a set of related packages and types (classes, abstract classes, interfaces, and more) with code, data files, and some static resources.

What does transitivity allow for when used in a module directive?

A 'requires' directive (irrespective of 'transitive') expresses that one module depends on some other module. The effect of the 'transitive' modifier is to cause additional modules to also depend on the other module.


1 Answers

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.)

like image 158
Nicolai Parlog Avatar answered Sep 21 '22 23:09

Nicolai Parlog