You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jira@kafka.apache.org by "Randall Hauch (Jira)" <ji...@apache.org> on 2019/10/17 02:15:00 UTC

[jira] [Resolved] (KAFKA-8340) ServiceLoader fails when used from isolated plugin path directory

     [ https://issues.apache.org/jira/browse/KAFKA-8340?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Randall Hauch resolved KAFKA-8340.
----------------------------------
      Reviewer: Randall Hauch
    Resolution: Fixed

> 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
>    Affects Versions: 2.3.0
>            Reporter: Chris Egerton
>            Assignee: Greg Harris
>            Priority: Major
>             Fix For: 2.0.2, 2.1.2, 2.2.2, 2.4.0, 2.5.0, 2.3.2
>
>
> 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
(v8.3.4#803005)