【问题标题】:Provider not a subtype inside docker container提供者不是 docker 容器内的子类型
【发布时间】:2018-10-06 23:42:11
【问题描述】:

情况

我正在开发一个应用程序,它使用 Java 的 URLClassLoaderServiceLoader 来加载 jar 文件。在这些 jar 文件中是实现我的接口的提供程序。文件夹结构如this post by oracle 中所述,意思是:

  • 该接口与插件中实现该接口的类(com.x.projectname.plugin.IInterface.java)位于同一目录中。在插件中,接口和实现它的类都在 com.x.projectname.plugin 文件夹中。
  • 在插件中有一个resources.META-INF.services目录,其中有一个文件:com.x.projectname.plugin.IInterface,内容如下: com.x.projectname.plugin.ClassThatImplementsIInterface

在我的本地机器上运行时(使用 Oracle JDK 1.8 162 和 OpenJDK 1.8 171 测试)插件加载正常,应用程序可以根据需要使用插件。

问题

在 docker 容器中运行主应用程序时,它无法加载所需的插件。 Docker 容器在机器上安装了一个文件夹,其中安装了插件。应用的docker镜像使用openjdk:8-jdk-alpine,但是不管我用不使用alpine版本,问题依然存在。

在尝试使用 Serviceloader.load() 加载插件时(参见 ServiceLoader.load(InterfaceName.class, ClassLoader loader)

它崩溃并出现以下错误:Provider com.x.projectname.plugin.InterfaceImplementingClass not a subtype.

这是堆栈跟踪的相关部分:

Caused by: java.util.ServiceConfigurationError: com.x.projectname.plugin.IInterface: Provider com.x.projectname.plugin.ImplementingClass not a subtype
        at java.util.ServiceLoader.fail(ServiceLoader.java:239) ~[na:1.8.0_151]
        at java.util.ServiceLoader.access$300(ServiceLoader.java:185) ~[na:1.8.0_151]
        at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:376) ~[na:1.8.0_151]
        at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:404) ~[na:1.8.0_151]
        at java.util.ServiceLoader$1.next(ServiceLoader.java:480) ~[na:1.8.0_151]
        at com.x.projectname.loader.PluginLoader.loadPlugins(PluginLoader.java:118) ~[classes!/:na]
        at com.x.projectname.loader.PluginLoader.initializePluginLoading(PluginLoader.java:67) ~[classes!/:na]
        at com.x.projectname.service.PluginService.<init>(PluginService.java:37) ~[classes!/:na]
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_151]
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_151]
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_151]

知道为什么它在 Docker 容器中运行时不会加载插件吗?

编辑 1:Dockerfile 和 docker run 命令

FROM openjdk:8-jdk-alpine
ARG JAR_FILE
ADD ${JAR_FILE} /CICD-dashboard.jar

# Remote debugging port for intelliJ == address
EXPOSE 50505
ENTRYPOINT [ "java", "-Xrunjdwp:transport=dt_socket,address=50505,suspend=n,server=y", "-jar", "/X-project.jar"]

docker 运行命令:

docker run -d -v /home/folder/pluginfolder:/pluginfolder -p=50505:50505 image-name

【问题讨论】:

  • 能否请您上传您用于构建映像的 Dockerfile 以及用于启动容器的 docker run 命令或 docker-compose.yml
  • @SaqibAhmed 当然,添加它!
  • 如果你在本地系统上使用java -jar ..运行这个jar文件,它可以工作吗?
  • 刚刚测试过,没有。这看起来很奇怪,因为通过 intelliJ 运行它确实有效。
  • 这并不奇怪。这就是一直以来的问题。这不是与 docker 相关的问题。你必须为你的 Java 代码创建一个Uberjar,以便它包含里面的所有依赖项。

标签: java docker urlclassloader serviceloader


【解决方案1】:

事实证明,答案正如 Saqib 在评论中所说:构建一个胖罐子。我为此使用了 shadowJar:http://imperceptiblethoughts.com/shadow/#configuring_shadow

【讨论】:

    猜你喜欢
    • 2016-09-28
    • 1970-01-01
    • 2019-09-14
    • 1970-01-01
    • 1970-01-01
    • 2017-03-11
    • 2017-03-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多