实例化动态加载的 class 实现现有接口

instantiate a dynamically loaded class implementing an existing interface

我已经看到几个类似问题的答案,但不幸的是 none 能够回答我的问题。
我有一个提供计算平台的 Web 应用程序,为了扩展它,我编写了一个接口,以便该应用程序会检查特定文件夹中是否有新添加的 jar 文件,以加载 classes 在运行时实现该接口。
我面临的问题是,即使 class 加载成功,我也无法将新创建的对象转换到我现有的界面 "ClassCastException"

ClassLoader sysClassLoader = ClassLoader.getSystemClassLoader();
URL directory = new URL("file:/Users/Abel/Desktop/Output/strategies/Classes/myJar.jar");
ClassLoader custom = new URLClassLoader(new URL[] {directory}, sysClassLoader);

Class strategyClass = custom.loadClass(className);
Object strategyObject = (Object) strategyClass.newInstance();
Strategy strategyInstance= (Strategy) strategyObject;

Strategy 当然是接口实现代码(以上)和 returns 生成的 Strategy 对象,所以我宁愿不使用反射来调用加载的 class 中包含的方法和我担心 LAO 最终会遇到同样的问题,因为该方法的参数也会被认为是不兼容的。
根据我的阅读,class 加载器将现有接口和沿 class 加载的接口视为两种不同的类型,因此例外。
有解决办法吗?

ClassCastException 建议找到具有该名称的(任何)class(不为空)。

可能来自(动态加载的二进制文件 class)来自不同的编译宿主(调用)源的编译?如果存在这种情况,class 具有相同的名称,但它是不同的 class。

或者加载器(主加载器和动态加载器)可能预加载了不同的源(罐子、class路径等)我不确定这部分答案

来自现实生活的示例:在同一框架的不同版本(在 Tomcat/jeety 上)开发的两个 webapp 可能与 class 具有相同名称但独立(如果容器不分开装载机)

试试下面的代码。问题是你的 jar 应该通过 CustomClassLoader 而不是默认系统 class 加载器加载。

// 在初始化期间 在某些方法中,如 initializeStrategy()

            CustomClassLoader customLoader =
                    new CustomClassLoader(getClass().getClassLoader(), new String[] {
                    <CLASSPATH_OF_IMPLEMENTOR_JAR>}
            try {
               specification = (SomeInterface) (customLoader.loadClass(<Implementor>).
                                newInstance());

            } catch (Exception ce) {
                ce.printStackTrace();
            }

//上传新 jar 后,通过(JSP 或 servlet)触发事件。在某些方法中添加此代码块,例如reloadNewStrategy();

try {
           if (specification; != null) {
                specification;.unload();
            }
            CustomClassLoader customLoader =
                    new CustomClassLoader(getClass().getClassLoader(), new String[] {
                    <CLASSPATH_OF_IMPLEMENTOR_JAR>});
            specification =
                    (SomeInterface) (customLoader.loadClass(<Implementor>).newInstance());
        } catch (Exception err) {
            err.printStackTrace();
        }
}

这里是你的策略界面 Implementor为策略执行对象。

我知道回答你自己的问题有点奇怪,但我还是会这样做,以防有人遇到同样的问题。

这是我一步一步做的。

  • 创建一个包含我的界面及其所需模型的 Jar 文件class。
  • 然后我将 jar 文件安装到我的本地存储库中,因为我使用 maven 进行依赖管理,因此不需要这一步。
  • 接下来我在一个单独的项目中创建了我的接口的实现,我在其中使用上述 Jar 文件作为依赖项。
  • 然后我在应用程序文件夹中添加了附加策略的 Jar 文件,该路径用于 class 加载。
  • 然后我将代码更改为:

    ClassLoader sysClassLoader = Strategie.class.getClassLoader();
    URL directory = new URL("file:" + path + "Strategies/Classes/" + strategie + ".jar");
    ClassLoader custom = new URLClassLoader(new URL[] {directory}, sysClassLoader);
    
    Class strategieClass = custom.loadClass(className);
    Object strategieObject = strategieClass.newInstance();
    Strategie strategieInstance= (Strategie) strategieObject;
    

更改 class 加载程序可避免出现 classDef not found 异常。