ServiceLoader in the JDK

David M. Lloyd david.lloyd at redhat.com
Thu May 24 08:43:13 PDT 2012


On 05/24/2012 10:08 AM, Jesse Glick wrote:
> On 05/24/2012 10:24 AM, David M. Lloyd wrote:
>> Rarely, if ever, do you want to
>> find every implementation of a service in the entire universe.
>
> Not the entire universe, but the set of modules loaded in the current
> module configuration (~ application). That is what Jigsaw "requires
> service" requests. So if that system is wanted, there needs to be an API
> call implementing that.

Then you're saying that Jigsaw proposes to introduce a new way to 
represent the current running application other than by class loader 
(and, by extension, module)?

>> In reality you most often want to find services relative to a specific
>> module/class loader - most often it's the running application
>
> That is exactly what "requires service" means - all services in the
> running application. Which need not map at all to any particular
> ClassLoader. (While it might be a particular Module, an "application
> entry point" module, that module's ClassLoader will _not_ generally be
> able to load all the app's services unless it happens to declare direct
> dependencies on every service provider.)

Do you mean running JVM in this case?

>> sometimes it's the API module itself
>
> Probably pointless, since that would only be able to load services
> defined in the same module; you might as well statically enumerate them.

This is useful in the case where implementation decisions are made at 
install time.  If an API usually has only a single implementation which 
makes sense for a platform - but it might be replaceable in special 
circumstances - this would be a good choice.  NIO or JAXP might fall 
into this category.

>> or something else altogether.
>
> In custom cases you ought to be able to use the existing
> ServiceLoader.load(Class,ClassLoader) with the same semantics as in JDK
> 7, i.e. loader.getResources(PREFIX+svc). It is debatable whether this
> method should also load "provided services" from Jigsaw modules which
> are visible to the supplied ClassLoader if that is in fact a
> ModuleClassLoader - that would enable you to load a subset of available
> services according to a subgraph of the application's dependency graph,
> conceivably useful but rather more complex and probably an advanced usage.
>
>> 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".
>
> TBD. It is used in some existing module systems (not OSGi AFAIK) since
> it sort of works and there is nothing clearly superseding it.

It works pretty well from our experience.  Logically, it makes sense to 
define the running application in terms of a module, be it a JAR run 
from the command line, a Java EE deployment, a JavaWS execution, or an 
explicitly named module.  It also makes sense to allow a supervisor to 
be able to change the current application on the fly; TCCL does this 
just fine.

> It is not
> entirely clear what types and resources should be visible to it, and it
> is even less clear how it should behave when multiple modules define a
> class with the same FQN, which ClassLoader cannot represent.

Well clearly a module cannot import more than one class with the same 
name any more than a class loader can.

> (ClassLoader _can_ represent multiple resources with the same path, but
> as I mentioned earlier this is not good enough for ServiceLoader since
> getResources returns a list of URL's with no indication of the "defining
> loader".)
>
>> Only in rare cases do you really want to have a concept of JVM-wide
>> service implementations
>
> To the contrary I would say this is the normal case for applications not
> running in a special multitenancy container such as EE. If you do have
> multiple apps in the JVM then (as mentioned in my last message) it is up
> to the module system to somehow ensure they do not interfere with one
> another, such as by offering distinct Module/Class instances, or using
> some implicit context like ThreadGroup. Looking for a subset of those
> service implementations available within the "current" application is
> another use case but probably more specialized.

Things like JSF or Hibernate which allow per-application plugins and 
components represent a very substantial segment of ServiceLoader usage. 
  I don't think it makes sense to treat this as a special advanced case.

>> you cannot assume that there is only one class with a given name
>> installed in the system
>
> No, you cannot, and correct implementations of service loading will not
> make such an assumption. JDK 7's ServiceLoader is broken in this regard
> in two ways: (1) absent a richer ClassLoader.getResources, it cannot
> tell which loader defined a service, so it cannot be sure to load the
> implementation class from that same loader, mishandling multiple copies
> of an implementation; (2) it fails to verify that a candidate
> implementation is actually assignable to the supplied interface, so it
> produces CCEs if you have multiple copies of the interface. In NetBeans
> we have a replacement service loader which fixes both these bugs.

I get what you're saying - basically you're speaking to the inability to 
use getResources to get a list of implementation names while at the same 
time associating the implementation name with its defining class loader.

In practice this hasn't been an issue for us - even with very involved 
module dependency graphs - since we typically export the service 
descriptor with the same or lesser scope than its implementation, thus 
ensuring that any module class loader which can see the descriptor can 
also see the implementation class.

The hair being split here could probably be summarized as the mechanism 
by which one may load service implementations from two different modules 
even if the implementation has the same class name.  In practice if you 
have a list of modules, you can iterate them and use the 
load-with-classloader variant of ServiceLoader and solve this problem 
neatly.  No matter what, you're dealing with iterating all candidate 
modules for a given service, so you have to know what they are at some 
level; I don't think that an enhanced getResources is necessary for this 
(convenient, yes; necessary, no).

-- 
- DML



More information about the jigsaw-dev mailing list