Chris Egerton created KAFKA-8340:
------------------------------------

             Summary: ServiceLoader fails when used from isolated plugin path 
directory
                 Key: KAFKA-8340
                 URL: https://issues.apache.org/jira/browse/KAFKA-8340
             Project: Kafka
          Issue Type: Bug
          Components: KafkaConnect
            Reporter: Chris Egerton


Under some circumstances, the {{ServiceLoader.load}} mechanism will fail when 
used from an isolated plugin path directory and return an incomplete (often 
empty) {{ServiceLoader}} instance.

 

To replicate:
 * Include a {{META-INF/services/...}} file in one of the JARS located in a 
plugin's directory with one or more implementations of that service listed 
inside. For the sake of example, let's say the name of this service is 
{{com.example.MyService}}
 * Program that plugin to invoke 
{{ServiceLoader.load(com.example.MyService.class)}}
 * Start the Connect framework, making sure this plugin is included on the 
plugin path and that it somehow invokes the {{ServiceLoader.load(...)}} method
 * Observe that the services loaded by that invocation do not include the ones 
described in the {{META-INF/services/...}} file contained in the JAR in the 
plugin's directory

 

This is because the 
[ServiceLoader.load(Class)|https://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html#load(java.lang.Class)]
 method uses the current thread's context classloader to locate resources and 
load services. The current thread's context classloader is, in most cases, an 
instance of {{DelegatingClassLoader}}, which will (unless asked to locate 
resources corresponding to a provider-configuration file for a REST extension 
or config provider) simply delegate resource location to the parent and, unless 
asked to locate a class for a recognized plugin, also delegate class loading to 
the parent. Thus, none of the plugin's JARs are scanned for either 
provider-configuration files or for actual service classes.

A viable workaround for some cases is to instead use the 
[ServiceLoader.load(Class, 
ClassLoader)|https://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html#load(java.lang.Class,%20java.lang.ClassLoader)]
 method, specifying the current class's classloader as the second argument. 
This causes the plugin's {{PluginClassLoader}}, which will scan all JARs in the 
plugin's directory to be used to locate resources and classes.

However, this may not be feasible in all cases, especially when working with 
external libraries that may be difficult or impossible to apply this workaround 
on.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to