mirror of https://github.com/halo-dev/halo
refactor: refresh the plugin wrapper when starting the plugin (#4023)
#### What type of PR is this? /kind improvement /kind bug /area core /area plugin /milestone 2.6.x #### What this PR does / why we need it: 修复插件重启后 MainClass 对象缓存未清除的问题 how to test it? 下载此插件: [plugin-starter-1.0.0-SNAPSHOT.jar.zip](https://github.com/halo-dev/halo/files/11620847/plugin-starter-1.0.0-SNAPSHOT.jar.zip) 安装并启动插件,会看到类似如下日志: ``` 测试从 [/var/folders/1z/3hlt62691tx63dxx6y0mryw00000gn/T/halo-plugin3709893537121269748.txt] 文件读取内容 插件启动成功! ``` 修改日志中给出的文件的内容后 reload 插件会看到`插件启动成功!` 后会跟随最新的文件内容则表示 MainClass 是最新的状态没有缓存。 #### Which issue(s) this PR fixes: Fixes #4016 #### Does this PR introduce a user-facing change? ```release-note 修复插件重启后 MainClass 对象缓存未清除的问题 ```pull/4081/head
parent
997a73d81b
commit
6d251a7f58
|
@ -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() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -289,8 +289,7 @@ public class PluginReconciler implements Reconciler<Request> {
|
|||
|
||||
void stateTransition(String name, Function<PluginState, Boolean> 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<Request> {
|
|||
break;
|
||||
}
|
||||
// update current state
|
||||
currentState = pluginWrapper.getPluginState();
|
||||
currentState = getPluginWrapper(name).getPluginState();
|
||||
} catch (Throwable e) {
|
||||
persistenceFailureStatus(name, e);
|
||||
throw e;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Refresh plugin wrapper by plugin name.</p>
|
||||
*
|
||||
* <p>It will be create a new plugin wrapper and replace old plugin wrapper to clean
|
||||
* {@link PluginWrapper#getPlugin()} cache object.</p>
|
||||
*
|
||||
* @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();
|
||||
|
|
Loading…
Reference in New Issue