Java › Class Loading & Bytecode Verification
How would you implement a custom ClassLoader to load classes from a non-standard source, such as loading plugin JARs dynamically at runtime, and what challenges arise with class unloading?
AdvancedAnswer
A custom ClassLoader extends ClassLoader (or URLClassLoader for JAR/URL-based loading) and overrides findClass() to define how to locate and read the raw bytecode from your custom source (a database, a plugin directory scanned at runtime, a network location), then calls defineClass() to convert those bytes into an actual Class object -- a major challenge is that a loaded class (and all its instances) can only be garbage collected once both the Class object itself AND the ClassLoader that loaded it become entirely unreferenced, meaning improperly discarding a plugin's ClassLoader reference (while still holding references to instances it created) causes a classloader leak, a notoriously tricky category of memory leak.
public class PluginClassLoader extends URLClassLoader {
public PluginClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
}
// Dynamically load a plugin JAR at runtime
URL pluginUrl = new File("plugins/my-plugin.jar").toURI().toURL();
PluginClassLoader loader = new PluginClassLoader(new URL[]{pluginUrl}, Main.class.getClassLoader());
Class<?> pluginClass = loader.loadClass("com.example.MyPlugin");
Object plugin = pluginClass.getDeclaredConstructor().newInstance();
// To allow unloading: discard ALL references to loader, pluginClass, and any instances it createdReal-world example A plugin-based application (like an IDE supporting third-party extensions) uses a dedicated ClassLoader per plugin, allowing plugins to be loaded and, when properly designed to release all references, later garbage collected and effectively "unloaded" without restarting the entire application, isolating each plugin's classes from others.