ServiceLoader in the JDK

David M. Lloyd david.lloyd at redhat.com
Thu May 24 07:24:16 PDT 2012


On 05/24/2012 07:40 AM, Jesse Glick wrote:
> On 05/24/2012 07:41 AM, Paul Sandoz wrote:
>> in module mode the only call that really makes sense is load(Class,
>>  ClassLoader) with the appropriate ClassLoader of the module.
>
> This does not make sense at all. load(Class,ClassLoader) is the one
> factory in ServiceLoader that has a dependable behavior and it should
> be left alone to behave as it did in JDK 7, whether running in module
> mode or not: loader.getResources(PREFIX + service.getName()). It
> should merely be documented that this variant is not generally what
> you want when running in module mode, since there is not likely to be
> any one ClassLoader which can load META-INF/** from every installed
> module

I believw this to be wrong thinking.  Rarely, if ever, do you want to
find every implementation of a service in the entire universe.  In
reality you most often want to find services relative to a specific
module/class loader - most often it's the running application but
sometimes it's the API module itself or something else altogether.

In other words, loading relative to a specified class loader is *nearly 
always* what you want.  This behavior works perfectly today in JDK 7 and 
should be left alone IMO.

> nor would this even be able to find services registered using
> "provides service" in module-info.class (*). In other words, this
> method should continue to work as before for old-style JAR services,
> and has nothing to do with Jigsaw services.
>
> The next question is what to do with load(Class) and
> loadInstalled(Class). The former picks up an implicit context in the
>  form of the thread context class loader, which will again not be
> useful at all for Jigsaw services, and the latter seems unusably
> vague in module mode (making as it does a bogus distinction between
> the "virtual machine" and the "application"). Probably they both need
> to be deprecated.

I agree with deprecating loadInstalled(), especially if the concept of 
an extension class loader is eliminated (better make a note of this for 
Java EE 7/8/whatever).  But the TCCL is still a valid concept - perhaps 
more so than ever - with modules and should continue to be supported to 
mean "the current application".

> That leaves the question of what Jigsaw-aware code should in fact
> call. Either introduce a new method in ServiceLoader:
>
> public static <S> ServiceLoader<S> load(Class<S> service, Class<?>
> reference);

Here's the problem.  Only in rare cases do you really want to have a 
concept of JVM-wide service implementations (think implementations of 
JDK module interfaces).  No matter what fancy mechanisms you add this 
will continue to be the case.  Primary reason #1 is that you cannot 
assume that there is only one class with a given name installed in the 
system.  If you break this, you will cause much suffering.

A service spec in the form of a class name is only valid or useful in 
the context of a module that knows how to load the class with that name 
AND has linked against the SAME service type as the implementation 
module.  System-wide service implementations logically should be 
registered by implementation module name with the module which defines 
the service.

> where 'reference' is the caller (**), or generally some class defined
> by a module which "requires service"; or leave ServiceLoader entirely
>  untouched and define a fresh API which is actually designed to work
> with Jigsaw services. You will note that the nonstatic members of
> ServiceLoader not in Iterable are just reload(), which should be
> unnecessary in module mode - if the module system supports dynamic
> changes, the service loader ought to be able to get notifications of
>  them automatically. (This method only makes sense when the impl is
> calling ClassLoader.getResources.) So maybe add to Class:
>
> public <S> Iterable<S> services(Class<S> service) { Module m =
> getModule(); return m != null ? m.somehowLoadProviders(service) :
> ServiceLoader.load(service); }
>
> which would result in the straightforward idiom:
>
> for (Interface impl : ThisCaller.class.services(Interface.class))
> {...}
>
> which would work correctly in module mode and tolerably in classpath
> mode.

More automatic caller determination = yuck.

> (**) As in earlier messages I am assuming that a Class and hence a
> Module instance uniquely identifies a module configuration, i.e. set
> of candidate providers. Someone needs to prototype
> multitenancy/isolates in Jigsaw to make sure this assumption is
> actually safe. If two applications are running at once in the VM,
> both of which happen to use the same version of a particular API
> module, you would expect that the JVM loads the bytecode for this API
> just once, yet it is TBD whether there is just one Module instance
> for this API (and one Class for each FQN in it), or whether each
> application gets its own private copy of the Module and Class's.

You definitely do not want to have modules spitting out private copies 
of classes.  This way lies serious madness.  One module should imply one 
class loader.
-- 
- DML



More information about the jigsaw-dev mailing list