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