英文:
How can I implement a custom class loader in Java that dynamically loads and executes Java code at runtime?
问题
我正在构建一个基于Java的应用程序,需要在运行时动态加载和执行插件类。每个插件由一个单独的Java类文件表示,实现了一个共同的接口Plugin。为了实现这一点,我需要实现一个自定义类加载器(PluginClassLoader),它可以从外部JAR文件中加载和实例化插件类。
我尝试在我的基于Java的应用程序中实现一个自定义类加载器,以便在运行时动态加载和执行插件类。我期望能成功地从外部JAR文件中加载和实例化插件类,并且它们可以在我的应用程序上下文中执行。
以下是我尝试的自定义类加载器示例:
public class PluginClassLoader extends ClassLoader {
public Class<?> loadPluginClass(String pluginFilePath) throws IOException {
byte[] pluginBytes = readPluginFile(pluginFilePath);
return defineClass(null, pluginBytes, 0, pluginBytes.length);
}
private byte[] readPluginFile(String pluginFilePath) throws IOException {
// 从外部JAR中读取插件文件的代码
}
}
我期望loadPluginClass
方法将从指定的文件路径加载插件类,并返回一个Class
对象,然后我可以使用它来实例化和执行插件。然而,在测试时,我遇到了类加载问题,并且对我尝试加载的插件类出现了ClassNotFoundExceptions
。
英文:
I am building a Java-based application that needs to dynamically load and execute plugin classes at runtime. Each plugin is represented by a separate Java class file that implements a common interface Plugin. To achieve this, I need to implement a custom class loader (PluginClassLoader) that can load and instantiate plugin classes from external JAR files.
I tried implementing a custom class loader in my Java-based application to dynamically load and execute plugin classes at runtime. I expected the plugin classes to be successfully loaded and instantiated from external JAR files, and for them to be available for execution within my application's context.
Here's an example of my attemted custom class loader:
public class PluginClassLoader extends ClassLoader {
public Class<?> loadPluginClass(String pluginFilePath) throws IOException {
byte[] pluginBytes = readPluginFile(pluginFilePath);
return defineClass(null, pluginBytes, 0, pluginBytes.length);
}
private byte[] readPluginFile(String pluginFilePath) throws IOException {
// Code to read the plugin file from external JAR
}
}
I expected that the loadPluginClass method would load the plugin class from the specified file path and return a Class
object that I could then use to instantiate and execute the plugin. However, when I tested it, I encountered class loading issues and ClassNotFoundExceptions
for the plugin classes that I tried to load.
答案1
得分: 1
你已经在自定义类加载器中添加了一个方法,用于根据自己的请求加载单个类。然而,如果插件由多个类组成,也就是说您试图加载的类依赖于插件内的其他类,JVM 将从您的加载器请求这些类。这些请求不会使用您的 loadPluginClass
方法,因为 JVM 无法知道它。相反,它将调用继承的方法 loadClass(String name, boolean resolve)
。
由于您既没有重写这个方法,也没有重写 findClass(String name)
方法(这将是首选方式),所以这个方法对于每个未经父加载器找到的类都会抛出 ClassNotFoundException
。解析依赖关系失败可能会导致依赖类的失败,因此即使您最初调用 loadPluginClass
也可能在 defineClass
调用时出现 ClassNotFoundException
。
由于您说您在插件中使用了 jar 文件,根本不需要实现自己的 ClassLoader
。只需使用已经存在的 URLClassLoader
,并将 jar 文件的 URL
传递给构造函数。或者对其进行子类化,以能够在其上调用 addURL
。请注意,将 File
转换为 URL
的正确方法是在 File
对象上调用 toURI().toURL()
而不是 toURL()
,以避免路径名中的空格或其他特殊字符引起问题。
此外,请确保在主应用程序未通过默认应用程序类加载器加载时将主应用程序的加载器指定为父加载器。
英文:
You have added a method to your custom class loader to load a single class on your own request. However, if the plugin consists of more than one class, i.e. the class you’re trying to load has dependencies to other classes within the plugin, the JVM will request those classes from your loader. Those requests won’t use your loadPluginClass
method which the JVM can’t know. Instead, it will invoke the inherited method loadClass(String name, boolean resolve)
.
Since you didn’t override neither this method nor the findClass(String name)
method (which would be the preferred way), this method will throw a ClassNotFoundException
for every class not found through the parent loader. A failure to resolve a dependency may cause a failure for the dependent class, so even your initial call to loadPluginClass
can fail with a ClassNotFoundException
at the defineClass
call.
Since you said that you are using jar files for your plugins, there is no need to implement your own ClassLoader
at all. Just use the already existing URLClassLoader
and pass the URL
of the jar file to the constructor. Or subclass it, to be able to call addURL
on it. Mind that the correct way to convert a File
to a URL
is to call toURI().toURL()
on the File
object instead of toURL()
, to avoid problems with spaces or other special characters in path names.
Further keep in mind to specify your main application’s loader as parent loader when the main application has not been loaded through the default application class loader.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论