Search code examples
javaclassloaderserviceloader

is Java ServiceLoader using the System Class Loader, or the Platform/Extension Class Loader?


Java JDK ServiceLoader as some complex information, and I have a hard time getting this one thing straight: Which class loader it uses.

This question concerns the range of JDKs from JDK8 to JDK17.

There are three static instantiation functions in the Oracle Java JDK docs:

  • static <S> ServiceLoader<S> load(Class<S> service) Creates a new service loader for the given service type, using the current thread's context class loader.
  • static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader) Creates a new service loader for the given service type and class loader.
  • static <S> ServiceLoader<S> loadInstalled(Class<S> service) Creates a new service loader for the given service type, using the extension class loader.

(in later JDK, it names the platform class loader instead).

The first two make sense to me. The third one is the confusing one.

To my knowledge the Extension/Platform Class Loader is a child of the Bootstrap Class Loader, but a parent to the System Class Loader. BootstrapCL--->PlatformCL-->SystemCL. The difference in operation being: the Platform/Extension Class Loader will load only from the java JDK and its ext subdirectory, while the System Class Loader loads from all the CLASSPATH, -cp and so on the current JVM has been provided with.

I would expect the System Class Loader to be used, but above documentation explicitly states the Extension or Platform Class Loader will be used.

Is that really so, and if so, why?


Solution

  • Even the oldest documentation is pretty clear:

    This method is intended for use when only installed providers are desired. The resulting service will only find and load providers that have been installed into the current Java virtual machine; providers on the application's class path will be ignored.

    The recent documentation still says the same

    So your knowledge is correct, only providers installed within the JDK will be found with this method and that’s intentional—even given by the method’s name.

    If you want to use the system class loader, you can simply use the load(Class) method, as the “current thread’s context class loader” defaults to the system class loader and you wouldn’t change it without a reason.

    The API note on load(Class) says that results should not be cached VM-wide, due to the caller dependency. So, one reason to use the loadInstalled method is to be able to cache the invariant JDK provided service implementations.
    Several JDK features use this (e.g. Charset/ CharsetProvider), to search the cached JDK providers first and only search for application specific providers if the first search failed. To stay with the example, it’s very uncommon to have application specific charsets.


    As a side note, the platform class loader does not load from an ext subdirectory. The mechanism has been abandoned with the introduction of the module system.