Restore context ClassLoader management during plugin lifecycle

refactor/restore-class-loader-after-switch
John Niang 2025-09-09 18:07:26 +08:00
parent 6992f1788c
commit 81fc98f8b0
No known key found for this signature in database
GPG Key ID: D7363C015BBCAA59
2 changed files with 19 additions and 6 deletions

View File

@ -70,11 +70,6 @@ public class DefaultPluginApplicationContextFactory implements PluginApplication
var pluginWrapper = pluginManager.getPlugin(pluginId);
var classLoader = pluginWrapper.getPluginClassLoader();
// Set the context ClassLoader to the plugin ClassLoader to ensure that
// any class loading operations performed by the context (e.g., initializing
// bean definitions, loading class resources during static initialization)
// use the correct ClassLoader.
Thread.currentThread().setContextClassLoader(classLoader);
/*
* Manually creating a BeanFactory and setting the plugin's ClassLoader is necessary
@ -189,7 +184,18 @@ public class DefaultPluginApplicationContextFactory implements PluginApplication
log.debug("Refreshing application context for plugin {}", pluginId);
sw.start("Refresh");
context.refresh();
// Set the context ClassLoader to the plugin ClassLoader to ensure that
// any class loading operations performed by the context (e.g., initializing
// bean definitions, loading class resources during static initialization)
// use the correct ClassLoader.
var previous = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(classLoader);
context.refresh();
} finally {
// reset the class loader to previous one to prevent resource leak
Thread.currentThread().setContextClassLoader(previous);
}
sw.stop();
log.debug("Refreshed application context for plugin {}", pluginId);
if (log.isDebugEnabled()) {

View File

@ -27,9 +27,11 @@ public class SpringPlugin extends Plugin {
public void start() {
log.info("Preparing starting plugin {}", pluginContext.getName());
var pluginId = pluginContext.getName();
var previous = Thread.currentThread().getContextClassLoader();
try {
// initialize context
this.context = contextFactory.create(pluginId);
Thread.currentThread().setContextClassLoader(this.context.getClassLoader());
log.info("Application context {} for plugin {} is created", this.context, pluginId);
var pluginOpt = context.getBeanProvider(Plugin.class)
@ -55,13 +57,17 @@ public class SpringPlugin extends Plugin {
this.stop();
// propagate exception to invoker.
throw t;
} finally {
Thread.currentThread().setContextClassLoader(previous);
}
}
@Override
public void stop() {
var previous = Thread.currentThread().getContextClassLoader();
try {
if (context != null) {
Thread.currentThread().setContextClassLoader(context.getClassLoader());
log.info("Before publishing plugin stopping event for plugin {}",
pluginContext.getName());
context.publishEvent(new SpringPluginStoppingEvent(this, this));
@ -74,6 +80,7 @@ public class SpringPlugin extends Plugin {
log.info("Stopped {} for plugin {}", this.delegate, pluginContext.getName());
}
} finally {
Thread.currentThread().setContextClassLoader(previous);
if (context instanceof ConfigurableApplicationContext configurableContext) {
log.info("Closing plugin context for plugin {}", pluginContext.getName());
configurableContext.close();