【问题标题】:Load external jar in Groovy on Websphere在 Websphere 上的 Groovy 中加载外部 jar
【发布时间】:2014-11-26 07:34:49
【问题描述】:

我有一个部署在 Websphere 8.5 上的应用程序,类加载配置为“Parent Last”。在应用程序中,我们使用GroovyScriptEngine 来运行一个 groovy 脚本文件。

在这个 groovy 脚本文件中,我们使用:

Thread.currentThread().getContextClassLoader().addURL( new URL("file:/test/ojdbc6.jar"))

加载外部 jar 文件。但它会导致错误:

groovy.lang.MissingMethodException: No signature of method: com.ibm.ws.classloader.CompoundClassLoader.addURL() is applicable for argument types: (java.net.URL) values: file:/test/ojdbc6.jar

我需要提到两件事:

  1. 相同的应用程序和 groovy 在 tomcat 上运行良好
  2. 如果我将 groovy 更改为 ClassLoader.systemClassLoader.addURL(new URL("file:/test/ojdbc6.jar")),那么它在 Websphere 和 tomcat 上都可以正常工作

我的问题

  1. 此错误是否与 Websphere 上的“上一个父级”设置有关?为什么?
  2. 为什么系统类加载器工作正常?

【问题讨论】:

    标签: groovy websphere classloader


    【解决方案1】:

    你必须检查javadoc,java.lang.ClassLoader,没有实现addURL()方法,它是由java.net.URLClassLoader实现的。 CompoundClassLoader 没有扩展它。所以为了安全起见,您应该始终使用instanceof 进行检查。如果没有,您可以尝试使用 getParent()getSystemClassLoader() 方法在堆栈中找到正确的类加载器。

    问:此错误是否与 Websphere 中的“上一个父级”设置有关?为什么?

    不完全是。然而,它与 WebSphere 中类加载器的模块化有关。在默认设置中,每个模块都由单独的类加载器加载,并且模块类加载器碰巧没有扩展URLClassLoader。如果您将服务器的服务器类加载器策略切换为单一,那么它将对所有应用程序使用单一类加载器,但它仍然是一个层次结构,因此它不会解决您的问题。有关WebSphere Classloaders 的详细信息,请查看此链接。

    引用文章

    当应用程序类加载器策略设置为 Single 时, 单个应用程序类加载器加载所有 EJB 模块、依赖项 JAR 文件和系统中的共享库。申请时 类加载器策略设置为 Multiple,然后每个应用程序接收 它自己的类加载器,用于加载 EJB 模块, 依赖 JAR 文件,以及该应用程序的共享库。

    但是对于您的问题,也许您应该考虑将ojdbc6.jar 添加为shared library?那么你就不需要在应用程序中嵌入代码来加载它了吗?

    这是查看类加载器层次结构的示例代码:

    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    do {
        System.out.println(classLoader.getClass().getName());
        System.out.println("Is URLClassLoader: " + (classLoader instanceof URLClassLoader));
        classLoader = classLoader.getParent();
    } while(classLoader != null);
    
    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    System.out.println("System: " + systemClassLoader.getClass().getName());
    System.out.println("Is URL: " + (systemClassLoader instanceof URLClassLoader));
    

    然后输出:

    SystemOut     O com.ibm.ws.classloader.CompoundClassLoader
    SystemOut     O Is URLClassLoader: false
    SystemOut     O com.ibm.ws.classloader.CompoundClassLoader
    SystemOut     O Is URLClassLoader: false
    SystemOut     O com.ibm.ws.classloader.ExtJarClassLoader
    SystemOut     O Is URLClassLoader: false
    SystemOut     O com.ibm.ws.classloader.ProtectionClassLoader
    SystemOut     O Is URLClassLoader: false
    SystemOut     O com.ibm.ws.bootstrap.ExtClassLoader
    SystemOut     O Is URLClassLoader: true
    SystemOut     O org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader
    SystemOut     O Is URLClassLoader: false
    SystemOut     O sun.misc.Launcher$AppClassLoader
    SystemOut     O Is URLClassLoader: true
    SystemOut     O sun.misc.Launcher$ExtClassLoader
    SystemOut     O Is URLClassLoader: true
    SystemOut     O System: sun.misc.Launcher$AppClassLoader
    SystemOut     O Is URLClassLoader: true
    

    【讨论】:

    • 我进入 websphere 管理控制台>>servers->server types->websphere application servers->server1->classloader policy,将其更改为 Single,但没有帮助。
    • @morven 我的错——即使是单个类加载器策略也在使用层次结构。检查我的更新。我不是 groovy 专家,但是如果您想加载驱动程序,可以通过数据源(如果可从 groovy 获得)或通过共享库来完成,那么您不必在应用程序中对加载 jar 进行硬编码。
    • 非常感谢您的解释。我可以只使用 ClassLoader.systemClassLoader.addURL(),它确实像我之前提到的那样工作,但不确定是否有任何副作用,因为我不熟悉它。
    • @morven 如果正在加载的库是自包含的并且不需要任何其他依赖项,那么您应该没问题。但是它将无法从您的应用程序中查找类,因为它们将由应用程序(子)类加载器加载。这些加载的库细节太少,需要自己测试。
    猜你喜欢
    • 2020-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多