mirror of https://github.com/halo-dev/halo
feat: support running plugins from JAR in development mode (#4589)
#### What type of PR is this? /kind feature /milestone 2.10.x /area core #### What this PR does / why we need it: 支持在开发模式下通过 JAR 运行插件 *从此版本开始 BasePlugin 的子类建议使用 BasePlugin(PluginContext context) 构造函数,而不要使用之前的 BasePlugin(PluginWrapper wrapper) 构造函数。BasePlugin(PluginWrapper wrapper) 构造函数将计划在后续版本移除* ,当移除构造函数后不再将 PluginWrapper 暴露给插件使用,它只应该在 halo core 使用。 how to test it? 1. 测试开发模式下配置的 `halo.plugin.fixed-plugin-path` 插件是否正确运行 2. 测试开发模式下通过 JAR 包安装插件是否正确运行 3. 测试生产模式下是否能通过项目目录的方式运行插件,期望是生产模式不可以运行开发模式的插件 4. 测试开发模式和生产模式的插件卸载功能是否正确 #### Which issue(s) this PR fixes: Fixes #2908 #### Does this PR introduce a user-facing change? ```release-note 支持在开发模式下通过 JAR 运行插件 ```pull/4668/head
parent
470b0de70d
commit
1f0cfc18e3
|
@ -3,6 +3,8 @@ package run.halo.app.plugin;
|
|||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.pf4j.Plugin;
|
||||
import org.pf4j.PluginWrapper;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* This class will be extended by all plugins and serve as the common class between a plugin and
|
||||
|
@ -14,12 +16,46 @@ import org.pf4j.PluginWrapper;
|
|||
@Slf4j
|
||||
public class BasePlugin extends Plugin {
|
||||
|
||||
protected PluginContext context;
|
||||
|
||||
@Deprecated
|
||||
public BasePlugin(PluginWrapper wrapper) {
|
||||
super(wrapper);
|
||||
log.info("Initialized plugin {}", wrapper.getPluginId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor a plugin with the given plugin context.
|
||||
* TODO Mark {@link PluginContext} as final to prevent modification.
|
||||
*
|
||||
* @param pluginContext plugin context must not be null.
|
||||
*/
|
||||
public BasePlugin(PluginContext pluginContext) {
|
||||
this.context = pluginContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* use {@link #BasePlugin(PluginContext)} instead of.
|
||||
*
|
||||
* @deprecated since 2.10.0
|
||||
*/
|
||||
public BasePlugin() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Compatible with old constructors, if the plugin is not use
|
||||
* {@link #BasePlugin(PluginContext)} constructor then base plugin factory will use this
|
||||
* method to set plugin context.
|
||||
*
|
||||
* @param context plugin context must not be null.
|
||||
*/
|
||||
final void setContext(PluginContext context) {
|
||||
Assert.notNull(context, "Plugin context must not be null");
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public PluginContext getContext() {
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package run.halo.app.plugin;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.pf4j.RuntimeMode;
|
||||
|
||||
/**
|
||||
* <p>This class will provide a context for the plugin, which will be used to store some
|
||||
* information about the plugin.</p>
|
||||
* <p>An instance of this class is provided to plugins in their constructor.</p>
|
||||
* <p>It's safe for plugins to keep a reference to the instance for later use.</p>
|
||||
* <p>This class facilitates communication with application and plugin manager.</p>
|
||||
* <p>Pf4j recommends that you use a custom PluginContext instead of PluginWrapper.</p>
|
||||
* <a href="https://github.com/pf4j/pf4j/blob/e4d7c7b9ea0c9a32179c3e33da1403228838944f/pf4j/src/main/java/org/pf4j/Plugin.java#L46">Use application custom PluginContext instead of PluginWrapper</a>
|
||||
*
|
||||
* @author guqing
|
||||
* @since 2.10.0
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public class PluginContext {
|
||||
private final String name;
|
||||
|
||||
private final String version;
|
||||
|
||||
private final RuntimeMode runtimeMode;
|
||||
}
|
|
@ -60,6 +60,7 @@ import run.halo.app.infra.utils.JsonUtils;
|
|||
import run.halo.app.infra.utils.PathUtils;
|
||||
import run.halo.app.infra.utils.YamlUnstructuredLoader;
|
||||
import run.halo.app.plugin.HaloPluginManager;
|
||||
import run.halo.app.plugin.HaloPluginWrapper;
|
||||
import run.halo.app.plugin.PluginConst;
|
||||
import run.halo.app.plugin.PluginExtensionLoaderUtils;
|
||||
import run.halo.app.plugin.PluginStartingError;
|
||||
|
@ -184,11 +185,12 @@ public class PluginReconciler implements Reconciler<Request> {
|
|||
Assert.notNull(name, "Plugin name must not be null");
|
||||
Assert.notNull(settingName, "Setting name must not be null");
|
||||
PluginWrapper pluginWrapper = getPluginWrapper(name);
|
||||
var runtimeMode = getRuntimeMode(name);
|
||||
|
||||
var resourceLoader =
|
||||
new DefaultResourceLoader(pluginWrapper.getPluginClassLoader());
|
||||
return PluginExtensionLoaderUtils.lookupExtensions(pluginWrapper.getPluginPath(),
|
||||
pluginWrapper.getRuntimeMode())
|
||||
runtimeMode)
|
||||
.stream()
|
||||
.map(resourceLoader::getResource)
|
||||
.filter(Resource::exists)
|
||||
|
@ -215,6 +217,7 @@ public class PluginReconciler implements Reconciler<Request> {
|
|||
return false;
|
||||
}
|
||||
|
||||
var runtimeMode = getRuntimeMode(pluginName);
|
||||
Optional<Setting> settingOption = lookupPluginSetting(pluginName, settingName)
|
||||
.map(setting -> {
|
||||
// This annotation is added to prevent it from being deleted when stopped.
|
||||
|
@ -802,11 +805,19 @@ public class PluginReconciler implements Reconciler<Request> {
|
|||
}
|
||||
|
||||
private boolean isDevelopmentMode(String name) {
|
||||
PluginWrapper pluginWrapper = haloPluginManager.getPlugin(name);
|
||||
RuntimeMode runtimeMode = haloPluginManager.getRuntimeMode();
|
||||
if (pluginWrapper != null) {
|
||||
runtimeMode = pluginWrapper.getRuntimeMode();
|
||||
return RuntimeMode.DEVELOPMENT.equals(getRuntimeMode(name));
|
||||
}
|
||||
|
||||
private RuntimeMode getRuntimeMode(String name) {
|
||||
var pluginWrapper = haloPluginManager.getPlugin(name);
|
||||
if (pluginWrapper == null) {
|
||||
return haloPluginManager.getRuntimeMode();
|
||||
}
|
||||
return RuntimeMode.DEVELOPMENT.equals(runtimeMode);
|
||||
if (pluginWrapper instanceof HaloPluginWrapper haloPluginWrapper) {
|
||||
return haloPluginWrapper.getRuntimeMode();
|
||||
}
|
||||
return Files.isDirectory(pluginWrapper.getPluginPath())
|
||||
? RuntimeMode.DEVELOPMENT
|
||||
: RuntimeMode.DEPLOYMENT;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,13 +23,17 @@ public class BasePluginFactory implements PluginFactory {
|
|||
return getPluginContext(pluginWrapper)
|
||||
.map(context -> {
|
||||
try {
|
||||
return context.getBean(BasePlugin.class);
|
||||
var basePlugin = context.getBean(BasePlugin.class);
|
||||
var pluginContext = context.getBean(PluginContext.class);
|
||||
basePlugin.setContext(pluginContext);
|
||||
return basePlugin;
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
log.info(
|
||||
"No bean named 'basePlugin' found in the context create default instance");
|
||||
DefaultListableBeanFactory beanFactory =
|
||||
context.getDefaultListableBeanFactory();
|
||||
BasePlugin pluginInstance = new BasePlugin();
|
||||
var pluginContext = beanFactory.getBean(PluginContext.class);
|
||||
BasePlugin pluginInstance = new BasePlugin(pluginContext);
|
||||
beanFactory.registerSingleton(Plugin.class.getName(), pluginInstance);
|
||||
return pluginInstance;
|
||||
}
|
||||
|
|
|
@ -108,6 +108,17 @@ public class HaloPluginManager extends DefaultPluginManager
|
|||
return new YamlPluginDescriptorFinder();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PluginWrapper createPluginWrapper(PluginDescriptor pluginDescriptor, Path pluginPath,
|
||||
ClassLoader pluginClassLoader) {
|
||||
// create the plugin wrapper
|
||||
log.debug("Creating wrapper for plugin '{}'", pluginPath);
|
||||
HaloPluginWrapper pluginWrapper =
|
||||
new HaloPluginWrapper(this, pluginDescriptor, pluginPath, pluginClassLoader);
|
||||
pluginWrapper.setPluginFactory(getPluginFactory());
|
||||
return pluginWrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void firePluginStateEvent(PluginStateEvent event) {
|
||||
rootApplicationContext.publishEvent(
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package run.halo.app.plugin;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import org.pf4j.PluginDescriptor;
|
||||
import org.pf4j.PluginManager;
|
||||
import org.pf4j.PluginWrapper;
|
||||
import org.pf4j.RuntimeMode;
|
||||
|
||||
/**
|
||||
* A wrapper over plugin instance for Halo.
|
||||
*
|
||||
* @author guqing
|
||||
* @since 2.10.0
|
||||
*/
|
||||
public class HaloPluginWrapper extends PluginWrapper {
|
||||
|
||||
private final RuntimeMode runtimeMode;
|
||||
|
||||
/**
|
||||
* Creates a new plugin wrapper to manage the specified plugin.
|
||||
*/
|
||||
public HaloPluginWrapper(PluginManager pluginManager, PluginDescriptor descriptor,
|
||||
Path pluginPath, ClassLoader pluginClassLoader) {
|
||||
super(pluginManager, descriptor, pluginPath, pluginClassLoader);
|
||||
this.runtimeMode = Files.isDirectory(pluginPath)
|
||||
? RuntimeMode.DEVELOPMENT : RuntimeMode.DEPLOYMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuntimeMode getRuntimeMode() {
|
||||
return runtimeMode;
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.pf4j.PluginRuntimeException;
|
||||
import org.pf4j.PluginWrapper;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.boot.env.PropertySourceLoader;
|
||||
|
@ -88,6 +89,8 @@ public class PluginApplicationInitializer {
|
|||
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
|
||||
stopWatch.stop();
|
||||
|
||||
beanFactory.registerSingleton("pluginContext", createPluginContext(plugin));
|
||||
// TODO deprecated
|
||||
beanFactory.registerSingleton("pluginWrapper", haloPluginManager.getPlugin(pluginId));
|
||||
|
||||
populateSettingFetcher(pluginId, beanFactory);
|
||||
|
@ -131,6 +134,15 @@ public class PluginApplicationInitializer {
|
|||
stopWatch.getTotalTimeMillis(), stopWatch.prettyPrint());
|
||||
}
|
||||
|
||||
PluginContext createPluginContext(PluginWrapper pluginWrapper) {
|
||||
if (pluginWrapper instanceof HaloPluginWrapper haloPluginWrapper) {
|
||||
return new PluginContext(haloPluginWrapper.getPluginId(),
|
||||
pluginWrapper.getDescriptor().getVersion(),
|
||||
haloPluginWrapper.getRuntimeMode());
|
||||
}
|
||||
throw new PluginRuntimeException("PluginWrapper must be instance of HaloPluginWrapper");
|
||||
}
|
||||
|
||||
private void populateSettingFetcher(String pluginName,
|
||||
DefaultListableBeanFactory listableBeanFactory) {
|
||||
ReactiveExtensionClient extensionClient =
|
||||
|
|
|
@ -5,6 +5,7 @@ import static run.halo.app.plugin.resources.BundleResourceUtils.getJsBundleResou
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@ -109,33 +110,7 @@ public class PluginAutoConfiguration {
|
|||
}
|
||||
} else {
|
||||
return new CompoundPluginLoader()
|
||||
.add(new DevelopmentPluginLoader(this) {
|
||||
|
||||
@Override
|
||||
protected PluginClassLoader createPluginClassLoader(Path pluginPath,
|
||||
PluginDescriptor pluginDescriptor) {
|
||||
return new PluginClassLoader(pluginManager, pluginDescriptor,
|
||||
getClass().getClassLoader(), ClassLoadingStrategy.APD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader loadPlugin(Path pluginPath,
|
||||
PluginDescriptor pluginDescriptor) {
|
||||
if (pluginProperties.getClassesDirectories() != null) {
|
||||
for (String classesDirectory :
|
||||
pluginProperties.getClassesDirectories()) {
|
||||
pluginClasspath.addClassesDirectories(classesDirectory);
|
||||
}
|
||||
}
|
||||
if (pluginProperties.getLibDirectories() != null) {
|
||||
for (String libDirectory :
|
||||
pluginProperties.getLibDirectories()) {
|
||||
pluginClasspath.addJarsDirectories(libDirectory);
|
||||
}
|
||||
}
|
||||
return super.loadPlugin(pluginPath, pluginDescriptor);
|
||||
}
|
||||
}, this::isDevelopment)
|
||||
.add(createDevelopmentPluginLoader(this), this::isDevelopment)
|
||||
.add(new JarPluginLoader(this) {
|
||||
@Override
|
||||
public ClassLoader loadPlugin(Path pluginPath,
|
||||
|
@ -145,9 +120,8 @@ public class PluginAutoConfiguration {
|
|||
getClass().getClassLoader(), ClassLoadingStrategy.APD);
|
||||
pluginClassLoader.addFile(pluginPath.toFile());
|
||||
return pluginClassLoader;
|
||||
|
||||
}
|
||||
}, this::isNotDevelopment);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,9 +141,8 @@ public class PluginAutoConfiguration {
|
|||
.setFixedPaths(pluginProperties.getFixedPluginPath());
|
||||
return new CompoundPluginRepository()
|
||||
.add(developmentPluginRepository, this::isDevelopment)
|
||||
.add(new JarPluginRepository(getPluginsRoots()), this::isNotDevelopment)
|
||||
.add(new DefaultPluginRepository(getPluginsRoots()),
|
||||
this::isNotDevelopment);
|
||||
.add(new JarPluginRepository(getPluginsRoots()))
|
||||
.add(new DefaultPluginRepository(getPluginsRoots()));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -181,6 +154,41 @@ public class PluginAutoConfiguration {
|
|||
return pluginManager;
|
||||
}
|
||||
|
||||
DevelopmentPluginLoader createDevelopmentPluginLoader(PluginManager pluginManager) {
|
||||
return new DevelopmentPluginLoader(pluginManager) {
|
||||
@Override
|
||||
protected PluginClassLoader createPluginClassLoader(Path pluginPath,
|
||||
PluginDescriptor pluginDescriptor) {
|
||||
return new PluginClassLoader(pluginManager, pluginDescriptor,
|
||||
getClass().getClassLoader(), ClassLoadingStrategy.APD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader loadPlugin(Path pluginPath,
|
||||
PluginDescriptor pluginDescriptor) {
|
||||
if (pluginProperties.getClassesDirectories() != null) {
|
||||
for (String classesDirectory :
|
||||
pluginProperties.getClassesDirectories()) {
|
||||
pluginClasspath.addClassesDirectories(classesDirectory);
|
||||
}
|
||||
}
|
||||
if (pluginProperties.getLibDirectories() != null) {
|
||||
for (String libDirectory :
|
||||
pluginProperties.getLibDirectories()) {
|
||||
pluginClasspath.addJarsDirectories(libDirectory);
|
||||
}
|
||||
}
|
||||
return super.loadPlugin(pluginPath, pluginDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(Path pluginPath) {
|
||||
return Files.exists(pluginPath)
|
||||
&& Files.isDirectory(pluginPath);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
String getSystemVersion() {
|
||||
return systemVersionSupplier.get().getNormalVersion();
|
||||
}
|
||||
|
|
|
@ -6,11 +6,12 @@ import java.util.Comparator;
|
|||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.pf4j.Extension;
|
||||
import org.pf4j.ExtensionFactory;
|
||||
import org.pf4j.Plugin;
|
||||
import org.pf4j.PluginManager;
|
||||
import org.pf4j.PluginRuntimeException;
|
||||
import org.pf4j.PluginWrapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
|
@ -52,46 +53,18 @@ import org.springframework.lang.Nullable;
|
|||
* @since 2.0.0
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class SpringExtensionFactory implements ExtensionFactory {
|
||||
|
||||
public static final boolean AUTOWIRE_BY_DEFAULT = true;
|
||||
|
||||
/**
|
||||
* The plugin manager is used for retrieving a plugin from a given extension class and as a
|
||||
* fallback supplier of an application context.
|
||||
*/
|
||||
protected final PluginManager pluginManager;
|
||||
|
||||
/**
|
||||
* Indicates if springs autowiring possibilities should be used.
|
||||
*/
|
||||
protected final boolean autowire;
|
||||
|
||||
public SpringExtensionFactory(PluginManager pluginManager) {
|
||||
this(pluginManager, AUTOWIRE_BY_DEFAULT);
|
||||
}
|
||||
|
||||
public SpringExtensionFactory(final PluginManager pluginManager, final boolean autowire) {
|
||||
this.pluginManager = pluginManager;
|
||||
this.autowire = autowire;
|
||||
if (!autowire) {
|
||||
log.warn(
|
||||
"Autowiring is disabled although the only reason for existence of this special "
|
||||
+ "factory is"
|
||||
+
|
||||
" supporting spring and its application context.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <T> T create(Class<T> extensionClass) {
|
||||
if (!this.autowire) {
|
||||
log.warn("Create instance of '" + nameOf(extensionClass)
|
||||
+ "' without using springs possibilities as"
|
||||
+ " autowiring is disabled.");
|
||||
return createWithoutSpring(extensionClass);
|
||||
}
|
||||
Optional<PluginApplicationContext> contextOptional =
|
||||
getPluginApplicationContextBy(extensionClass);
|
||||
if (contextOptional.isPresent()) {
|
||||
|
@ -154,52 +127,38 @@ public class SpringExtensionFactory implements ExtensionFactory {
|
|||
|
||||
protected <T> Optional<PluginApplicationContext> getPluginApplicationContextBy(
|
||||
final Class<T> extensionClass) {
|
||||
final Plugin plugin = Optional.ofNullable(this.pluginManager.whichPlugin(extensionClass))
|
||||
return Optional.ofNullable(this.pluginManager.whichPlugin(extensionClass))
|
||||
.map(PluginWrapper::getPlugin)
|
||||
.orElse(null);
|
||||
|
||||
final PluginApplicationContext applicationContext;
|
||||
|
||||
if (plugin instanceof BasePlugin) {
|
||||
log.debug(
|
||||
" Extension class ' " + nameOf(extensionClass) + "' belongs to halo-plugin '"
|
||||
+ nameOf(plugin)
|
||||
+ "' and will be autowired by using its application context.");
|
||||
applicationContext = ExtensionContextRegistry.getInstance()
|
||||
.getByPluginId(plugin.getWrapper().getPluginId());
|
||||
return Optional.of(applicationContext);
|
||||
} else if (this.pluginManager instanceof HaloPluginManager && plugin != null) {
|
||||
log.debug(" Extension class ' " + nameOf(extensionClass)
|
||||
+ "' belongs to a non halo-plugin (or main application)"
|
||||
+ " '" + nameOf(plugin)
|
||||
+ ", but the used Halo plugin-manager is a spring-plugin-manager. Therefore"
|
||||
+ " the extension class will be autowired by using the managers application "
|
||||
+ "contexts");
|
||||
String pluginId = plugin.getWrapper().getPluginId();
|
||||
applicationContext = ((HaloPluginManager) this.pluginManager)
|
||||
.getPluginApplicationContext(pluginId);
|
||||
} else {
|
||||
log.warn(" No application contexts can be used for instantiating extension class '"
|
||||
+ nameOf(extensionClass) + "'."
|
||||
+ " This extension neither belongs to a halo-plugin (id: '" + nameOf(plugin)
|
||||
+ "') nor is the used"
|
||||
+ " plugin manager a spring-plugin-manager (used manager: '"
|
||||
+ nameOf(this.pluginManager.getClass()) + "')."
|
||||
+ " At perspective of PF4J this seems highly uncommon in combination with a factory"
|
||||
+ " which only reason for existence"
|
||||
+ " is using spring (and its application context) and should at least be reviewed. "
|
||||
+ "In fact no autowiring can be"
|
||||
+ " applied although autowire flag was set to 'true'. Instantiating will fallback "
|
||||
+ "to standard Java reflection.");
|
||||
applicationContext = null;
|
||||
}
|
||||
|
||||
return Optional.ofNullable(applicationContext);
|
||||
.map(plugin -> {
|
||||
if (plugin instanceof BasePlugin basePlugin) {
|
||||
return basePlugin;
|
||||
}
|
||||
throw new PluginRuntimeException(
|
||||
"The plugin must be an instance of BasePlugin");
|
||||
})
|
||||
.map(plugin -> {
|
||||
var pluginName = plugin.getContext().getName();
|
||||
if (this.pluginManager instanceof HaloPluginManager haloPluginManager) {
|
||||
log.debug(" Extension class ' " + nameOf(extensionClass)
|
||||
+ "' belongs to a non halo-plugin (or main application)"
|
||||
+ " '" + nameOf(plugin)
|
||||
+ ", but the used Halo plugin-manager is a spring-plugin-manager. Therefore"
|
||||
+ " the extension class will be autowired by using the managers "
|
||||
+ "application "
|
||||
+ "contexts");
|
||||
return haloPluginManager.getPluginApplicationContext(pluginName);
|
||||
}
|
||||
log.debug(
|
||||
" Extension class ' " + nameOf(extensionClass) + "' belongs to halo-plugin '"
|
||||
+ nameOf(plugin)
|
||||
+ "' and will be autowired by using its application context.");
|
||||
return ExtensionContextRegistry.getInstance().getByPluginId(pluginName);
|
||||
});
|
||||
}
|
||||
|
||||
private String nameOf(final Plugin plugin) {
|
||||
private String nameOf(final BasePlugin plugin) {
|
||||
return Objects.nonNull(plugin)
|
||||
? plugin.getWrapper().getPluginId()
|
||||
? plugin.getContext().getName()
|
||||
: "system";
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ import run.halo.app.extension.controller.Reconciler;
|
|||
import run.halo.app.infra.utils.FileUtils;
|
||||
import run.halo.app.infra.utils.JsonUtils;
|
||||
import run.halo.app.plugin.HaloPluginManager;
|
||||
import run.halo.app.plugin.HaloPluginWrapper;
|
||||
import run.halo.app.plugin.PluginConst;
|
||||
import run.halo.app.plugin.PluginStartingError;
|
||||
|
||||
|
@ -69,7 +70,7 @@ class PluginReconcilerTest {
|
|||
ExtensionClient extensionClient;
|
||||
|
||||
@Mock
|
||||
PluginWrapper pluginWrapper;
|
||||
HaloPluginWrapper pluginWrapper;
|
||||
|
||||
@Mock
|
||||
ApplicationEventPublisher eventPublisher;
|
||||
|
|
Loading…
Reference in New Issue