实例化动态加载的 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 异常。
我已经看到几个类似问题的答案,但不幸的是 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 异常。