Java EE WebApp ServiceLoader 加载外部 jar 作为插件
Java EE WebApp ServiceLoader loading external jar as plugin
我有一个非常简单的 POC 设置,我在 wildfly 9 上部署了一个 JEE7 webapp。
通过 jaxRs 资源端点,我可以触发 "plugin loader".
PluginLoader 确实使用目录并扫描目录中的 jar 文件,然后将这些 URL 送入 URLClassLoader。
之后,我使用 ServiceLoader 从这些 URL 加载简单接口的实现。
当 ServiceLoader 开始迭代找到的实现时,我收到此错误:
Caused by: java.util.ServiceConfigurationError: com.test.MyIface: Provider com.test.MyImpl not a subtype
结构也很简单:
MyIface.jar 是界面。
MyImpl.jar 是 MyIface 的一个实现,同时它包含一个 META-INF/services 文件,其中包含 MyIface 的正确命名和内容。
webapp本身当然只知道MyIFace。
在 JavaSE 中使用一个简单的主入口点并从那里调用加载器,一切正常。
在 JavaEE 中,服务文件似乎被忽略了……至少这是我从异常中得到的。
我放在src/main/resources/META-INF/services
在 src/main/resource/WEB-INF/类/META-INF/services 中(正如我在 SPI 和 webapps 的上下文中读到的那样)
为了使其正常工作,必须遵循以下 2 个步骤:
- 实例化一个
ClassLoader
(stock URLClassLoader
可以)它知道目标 jar 和 网络的 classloader应用。
- 加载服务实现显然需要知道目标jar
- 它需要将 Web 应用程序的 classloader 作为父级,以便所有 classloader 共享接口 class;否则,即使自定义 classloader 加载界面,你也会 运行
ClassCastException
像 "MyIface is not an instance of MyIface"
- 指定您使用
ServiceLoader.load(Class, ClassLoader)
方法创建的 classloader
我有一个非常简单的 POC 设置,我在 wildfly 9 上部署了一个 JEE7 webapp。 通过 jaxRs 资源端点,我可以触发 "plugin loader".
PluginLoader 确实使用目录并扫描目录中的 jar 文件,然后将这些 URL 送入 URLClassLoader。
之后,我使用 ServiceLoader 从这些 URL 加载简单接口的实现。
当 ServiceLoader 开始迭代找到的实现时,我收到此错误:
Caused by: java.util.ServiceConfigurationError: com.test.MyIface: Provider com.test.MyImpl not a subtype
结构也很简单: MyIface.jar 是界面。 MyImpl.jar 是 MyIface 的一个实现,同时它包含一个 META-INF/services 文件,其中包含 MyIface 的正确命名和内容。 webapp本身当然只知道MyIFace。
在 JavaSE 中使用一个简单的主入口点并从那里调用加载器,一切正常。 在 JavaEE 中,服务文件似乎被忽略了……至少这是我从异常中得到的。
我放在src/main/resources/META-INF/services 在 src/main/resource/WEB-INF/类/META-INF/services 中(正如我在 SPI 和 webapps 的上下文中读到的那样)
为了使其正常工作,必须遵循以下 2 个步骤:
- 实例化一个
ClassLoader
(stockURLClassLoader
可以)它知道目标 jar 和 网络的 classloader应用。- 加载服务实现显然需要知道目标jar
- 它需要将 Web 应用程序的 classloader 作为父级,以便所有 classloader 共享接口 class;否则,即使自定义 classloader 加载界面,你也会 运行
ClassCastException
像 "MyIface is not an instance of MyIface"
- 指定您使用
ServiceLoader.load(Class, ClassLoader)
方法创建的 classloader