【问题标题】:Loading same class from different jars从不同的 jar 加载相同的类
【发布时间】:2013-08-23 04:46:18
【问题描述】:

我有一个新的小 Swing 项目,我需要从两个不同的 jarsm 加载相同的类,这些 jars 是第三方,所以我没有源代码。

例如,我需要从两个 jar 中加载 myClass。 jar1.jar jar2.jar

只是我需要做的:

public void doMyClassLogicVersion1() {

    Loader = // here i need to load jar1.myClass.
    // myClass need a two params to initialize it in the normal case
    // also i need to access its static members
    // do the logic of myClass version1

}

public void doMyClassLogicVersion2() {

    Loader = // here i need to load jar2.myClass.
    // myClass need a two params to initialize it in the normal case
    // also i need to access its static members
    // do the logic of myClass version2
}

我可以那样做吗,我知道这样做不好,但我真的需要。

【问题讨论】:

    标签: java classloader


    【解决方案1】:

    您可以相对轻松地将新代码加载到新的类加载器中:

    案例1:如果你的类在当前上下文中有一个公共的父接口(或类),例如Runnable,你可以使用这个代码:

    public void doMyClassLogicVersion1() {
        ClassLoader loader = URLClassLoader.newInstance(
         new URL[] { yourURL1 },   
         getClass().getClassLoader()
        );
        Class<?> clazz = Class.forName("mypackage.MyClass", true, loader);
        Class<? extends Runnable> runClass = clazz.asSubclass(Runnable.class);
        // Avoid Class.newInstance, for it is evil.
        Constructor<? extends Runnable> ctor = runClass.getConstructor();
        Runnable doRun = ctor.newInstance();
        doRun.run();
    }
    
    public void doMyClassLogicVersion2() {
        ClassLoader loader = URLClassLoader.newInstance(
         new URL[] { yourURL2 },   
         getClass().getClassLoader()
        );
        Class<?> clazz = Class.forName("mypackage.MyClass", true, loader);
        Class<? extends Runnable> runClass = clazz.asSubclass(Runnable.class);
        // Avoid Class.newInstance, for it is evil.
        Constructor<? extends Runnable> ctor = runClass.getConstructor();
        Runnable doRun = ctor.newInstance();
        doRun.run();
    }
    

    案例 2:如果类没有共同的父类:

    public void doMyClassLogicVersion1() {
        ClassLoader loader = URLClassLoader.newInstance(
         new URL[] { yourURL1 },   
         getClass().getClassLoader()
        );
        Class<?> clazz = Class.forName("mypackage.MyClass", true, loader);
        // Avoid Class.newInstance, for it is evil.
        Constructor<?> ctor = runClass.getConstructor();
        Object obj = ctor.newInstance();
    
        String methodName = "getName";
    
        java.lang.reflect.Method method;
        try {
          method = clazz.getMethod(methodName, param1.class, param2.class, ..);
        } catch (SecurityException e) {
          // ...
        } catch (NoSuchMethodException e) {
          // ...
        }
    
        try {
          method.invoke(obj, arg1, arg2,...);
        } catch (IllegalArgumentException e) {
          // ...
        } catch (IllegalAccessException e) {
          // ...
        } catch (InvocationTargetException e) {
          // ...
        }
    }
    
    public void doMyClassLogicVersion2() {
        ClassLoader loader = URLClassLoader.newInstance(
         new URL[] { yourURL2 },   
         getClass().getClassLoader()
        );
        Class<?> clazz = Class.forName("mypackage.MyClass", true, loader);
        // Avoid Class.newInstance, for it is evil.
        Constructor<?> ctor = runClass.getConstructor();
        Object obj = ctor.newInstance();
    
        String methodName = "getName";
    
        java.lang.reflect.Method method;
        try {
          method = clazz.getMethod(methodName, param1.class, param2.class, ..);
        } catch (SecurityException e) {
          // ...
        } catch (NoSuchMethodException e) {
          // ...
        }
    
        try {
          method.invoke(obj, arg1, arg2,...);
        } catch (IllegalArgumentException e) {
          // ...
        } catch (IllegalAccessException e) {
          // ...
        } catch (InvocationTargetException e) {
          // ...
        }
    }
    

    【讨论】:

    • 已删除问题的答案:为什么是 URLClassLoader.newInstance? URLClassLoader.newInstance 为指定的 URL 和默认父类加载器创建 URLClassLoader 的新实例。如果安装了安全管理器,则此方法返回的 URLClassLoader 的 loadClass 方法将在加载类之前调用​​ SecurityManager.checkPackageAccess。来源:download.java.net/jdk8/docs/api/java/net/…
    • 感谢 mohammad,但我仍然需要调用包含已加载类的特定方法。所以这将与您的代码一起提供。并且 myClass 构造函数显示包含两个 patams。
    • 这两个类有相同的父类吗?如果有,那么您可以在我的代码中用 Runnable 替换该父类。
    • 否则,如果它们没有共同的父类,仍然可以通过反射来实现。
    • 如果对您有用,请不要忘记将其标记为答案!
    【解决方案2】:

    是的,你可以做到。为避免出现问题,我建议您不要将任何 jar 放在常规 CLASSPATH 中,创建 2 个不同的线程,并将每个线程的 ContextClassLoader 设置为相应的 jar,然后再启动它们。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-09
      • 1970-01-01
      • 2018-04-01
      • 2018-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多