diff --git a/api/src/main/java/run/halo/app/plugin/BasePlugin.java b/api/src/main/java/run/halo/app/plugin/BasePlugin.java index ed186f24b..f513514fe 100644 --- a/api/src/main/java/run/halo/app/plugin/BasePlugin.java +++ b/api/src/main/java/run/halo/app/plugin/BasePlugin.java @@ -2,7 +2,6 @@ package run.halo.app.plugin; import lombok.extern.slf4j.Slf4j; import org.pf4j.Plugin; -import org.pf4j.PluginManager; import org.pf4j.PluginWrapper; /** @@ -15,12 +14,12 @@ import org.pf4j.PluginWrapper; @Slf4j public class BasePlugin extends Plugin { + @Deprecated public BasePlugin(PluginWrapper wrapper) { super(wrapper); log.info("Initialized plugin {}", wrapper.getPluginId()); } - private PluginManager getPluginManager() { - return getWrapper().getPluginManager(); + public BasePlugin() { } } diff --git a/application/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java b/application/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java index b8cedd315..e4cb26bfa 100644 --- a/application/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java +++ b/application/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java @@ -289,8 +289,7 @@ public class PluginReconciler implements Reconciler { void stateTransition(String name, Function stateAction, PluginState desiredState) { - PluginWrapper pluginWrapper = getPluginWrapper(name); - PluginState currentState = pluginWrapper.getPluginState(); + PluginState currentState = getPluginWrapper(name).getPluginState(); int maxRetries = PluginState.values().length; for (int i = 0; i < maxRetries && currentState != desiredState; i++) { try { @@ -303,7 +302,7 @@ public class PluginReconciler implements Reconciler { break; } // update current state - currentState = pluginWrapper.getPluginState(); + currentState = getPluginWrapper(name).getPluginState(); } catch (Throwable e) { persistenceFailureStatus(name, e); throw e; diff --git a/application/src/main/java/run/halo/app/plugin/BasePluginFactory.java b/application/src/main/java/run/halo/app/plugin/BasePluginFactory.java index 805f7e99f..c769ab8e2 100644 --- a/application/src/main/java/run/halo/app/plugin/BasePluginFactory.java +++ b/application/src/main/java/run/halo/app/plugin/BasePluginFactory.java @@ -29,7 +29,7 @@ public class BasePluginFactory implements PluginFactory { "No bean named 'basePlugin' found in the context create default instance"); DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory(); - BasePlugin pluginInstance = new BasePlugin(pluginWrapper); + BasePlugin pluginInstance = new BasePlugin(); beanFactory.registerSingleton(Plugin.class.getName(), pluginInstance); return pluginInstance; } diff --git a/application/src/main/java/run/halo/app/plugin/HaloPluginManager.java b/application/src/main/java/run/halo/app/plugin/HaloPluginManager.java index b748e04c7..7abcb1d5f 100644 --- a/application/src/main/java/run/halo/app/plugin/HaloPluginManager.java +++ b/application/src/main/java/run/halo/app/plugin/HaloPluginManager.java @@ -229,7 +229,11 @@ public class HaloPluginManager extends DefaultPluginManager private PluginState doStartPlugin(String pluginId) { checkPluginId(pluginId); - PluginWrapper pluginWrapper = getPlugin(pluginId); + // refresh plugin to ensure cache object of PluginWrapper.plugin is up-to-date + // see gh-4016 to know why we need this + // TODO if has a better way to do this? + PluginWrapper pluginWrapper = refreshPluginWrapper(pluginId); + checkExtensionFinderReady(pluginWrapper); PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor(); @@ -423,6 +427,37 @@ public class HaloPluginManager extends DefaultPluginManager } } + /** + *

Refresh plugin wrapper by plugin name.

+ * + *

It will be create a new plugin wrapper and replace old plugin wrapper to clean + * {@link PluginWrapper#getPlugin()} cache object.

+ * + * @param pluginName plugin name + * @return refreshed plugin wrapper instance, plugin cache object will be null + * @throws IllegalArgumentException if plugin not found + */ + protected synchronized PluginWrapper refreshPluginWrapper(String pluginName) { + checkPluginId(pluginName); + // get old plugin wrapper + PluginWrapper pluginWrapper = getPlugin(pluginName); + // create new plugin wrapper to replace old plugin wrapper + PluginWrapper refreshed = copyPluginWrapper(pluginWrapper); + this.plugins.put(pluginName, refreshed); + return refreshed; + } + + @NonNull + PluginWrapper copyPluginWrapper(@NonNull PluginWrapper pluginWrapper) { + PluginWrapper refreshed = + createPluginWrapper(pluginWrapper.getDescriptor(), pluginWrapper.getPluginPath(), + pluginWrapper.getPluginClassLoader()); + refreshed.setPluginFactory(getPluginFactory()); + refreshed.setPluginState(pluginWrapper.getPluginState()); + refreshed.setFailedException(pluginWrapper.getFailedException()); + return refreshed; + } + @Override public void destroy() throws Exception { stopPlugins();