I'm trying to understand the Java ServiceLoader
concepts, working mechanism and concrete use cases, but find the official documentation too abstract and confusing.
First of all, documentation outlines services and service providers. Service is a set of interfaces and abstract classes packaged in a jar archive (API library). Service provider is a set of classes that implements or extends the API, packaged in a distinct jar file (Provider library).
So far so good, but then the documentation gets confusing.
For the purpose of loading, a service is represented by a single type, that is, a single interface or abstract class. (A concrete class can be used, but this is not recommended.) A provider of a given service contains one or more concrete classes that extend this service type with data and code specific to the provider. The provider class is typically not the entire provider itself but rather a proxy which contains enough information to decide whether the provider is able to satisfy a particular request together with code that can create the actual provider on demand. The details of provider classes tend to be highly service-specific; no single class or interface could possibly unify them, so no such type is defined here. The only requirement enforced by this facility is that provider classes must have a zero-argument constructor so that they can be instantiated during loading.
So what are actually Service type and Provider class? I get the impression, that service type is is a facade in the API library, and provider class is the implementation of this facade interface in the provider library, the class which ServiceLoader
actually loads. Is this correct? But it still doesn't make much sense to me, how all the components ties together.
And what is meant by provider class being a proxy to decide whether the provider is able to satisfy a particular request together with code that can create the actual provider on demand? No unifying type could be defined where? Basically all of this paragraph is confusing, and I would like to hear more comprehensible explanation by a concrete example.
Then about provider configuration file...
A service provider is identified by placing a provider-configuration file in the resource directory META-INF/services. The file's name is the fully-qualified binary name of the service's type. The file contains a list of fully-qualified binary names of concrete provider classes, one per line ...
The configuration file naming a particular provider need not be in the same jar file or other distribution unit as the provider itself. The provider must be accessible from the same class loader that was initially queried to locate the configuration file; note that this is not necessarily the class loader from which the file was actually loaded.
Does this mean for an API with service type of org.foo.BarServiceType, in the classpath there must exists the provider jar with a class implementing this type and META-INF/services/org.foo.BarServiceType
named provider configuration file listing this provider class, all accessible by the same Classloader
which loaded ServiceLoader
to find and bind the provider on the API?
From the classloader perspective, accessible means the provider configuration file and provider library may be provided outside of the package, upper from the hierarchy, i.e. from a container or other middleware.
The provider configuration file lists provider classes, and may be bundled in the provider package (why would it list multiple classes anyway if bundled?) or come from outside. But which approach is more common: to provide the configuration file among the provider, or provide the file listing a set of supported providers from within the API library itself? Or is the latter a misconception?
Finally about ServiceLoader
Where the ServiceLoader
is actually instantiated and called to load the service provider? Does this happens in a factory method provided by the API library? For example, does LoggingFactory.getLogger(clazz)
of SLF4J internally delegate to ServiceLoader
, which uses reflection to read the provider configuration files and load the services?.
How does the service loading mechanism concerns situations, wheres there are either multiple providers with their configuration files present, or there is provider configuration file entry but not the class itself?
And what are some other concrete use cases of ServiceLoader
outside of logging frameworks? How much it is utilized under the hood on popular frameworks like Java EE, Spring and Hibernate? What are some alternatives to service loading mechanism with loosely coupled API--provider binding, or is there?
proxy
has some more dynamic behavior here – Adriannaadrianne