mirror of https://github.com/halo-dev/halo
feat: plugin class is registered as a bean at startup (#2255)
<!-- Thanks for sending a pull request! Here are some tips for you: 1. 如果这是你的第一次,请阅读我们的贡献指南:<https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>。 1. If this is your first time, please read our contributor guidelines: <https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>. 2. 请根据你解决问题的类型为 Pull Request 添加合适的标签。 2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request. 3. 请确保你已经添加并运行了适当的测试。 3. Ensure you have added or ran the appropriate tests for your PR. --> #### What type of PR is this? /kind feature /milestone 2.0 /area core <!-- 添加其中一个类别: Add one of the following kinds: /kind bug /kind cleanup /kind documentation /kind feature /kind improvement 适当添加其中一个或多个类别(可选): Optionally add one or more of the following kinds if applicable: /kind api-change /kind deprecation /kind failing-test /kind flake /kind regression --> #### What this PR does / why we need it: 插件 plugin.yaml 中不用在写 pluginClass 属性,插件的生命周期类通过标注 `@Component` 注解在启动时通过 PluginApplicationContext 依赖注入并创建实例,这得益于每个插件都有一个单独的 PluginApplicationContext 插件启动时可以将PluginWrapper 放到 Context 以支撑 pluginClass 实例的创建 ```yaml apiVersion: plugin.halo.run/v1alpha1 kind: Plugin metadata: # The name defines how the plugin is invoked,A unique name name: PluginTemplate spec: pluginClass: run.halo.template.TemplatePlugin ``` 现在只需要如下方式即可无需配置 pluginClass ```java @Component public class TemplatePlugin extends BasePlugin {} ``` #### Which issue(s) this PR fixes: <!-- PR 合并时自动关闭 issue。 Automatically closes linked issue when PR is merged. 用法:`Fixes #<issue 号>`,或者 `Fixes (粘贴 issue 完整链接)` Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`. --> Fixes # #### Special notes for your reviewer: /cc @halo-dev/sig-halo #### Does this PR introduce a user-facing change? <!-- 如果当前 Pull Request 的修改不会造成用户侧的任何变更,在 `release-note` 代码块儿中填写 `NONE`。 否则请填写用户侧能够理解的 Release Note。如果当前 Pull Request 包含破坏性更新(Break Change), Release Note 需要以 `action required` 开头。 If no, just write "NONE" in the release-note block below. If yes, a release note is required: Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required". --> ```release-note None ```pull/2249/head
parent
ca3cff277a
commit
49ea6fbdec
|
@ -16,7 +16,6 @@ import org.pf4j.PluginState;
|
|||
import org.springframework.lang.NonNull;
|
||||
import run.halo.app.extension.AbstractExtension;
|
||||
import run.halo.app.extension.GVK;
|
||||
import run.halo.app.plugin.BasePlugin;
|
||||
|
||||
/**
|
||||
* A custom resource for Plugin.
|
||||
|
@ -74,7 +73,8 @@ public class Plugin extends AbstractExtension {
|
|||
*/
|
||||
private String requires = "*";
|
||||
|
||||
private String pluginClass = BasePlugin.class.getName();
|
||||
@Deprecated
|
||||
private String pluginClass;
|
||||
|
||||
private Boolean enabled = false;
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ public class PluginReconciler implements Reconciler {
|
|||
|
||||
private void ensureSpecUpToDateWhenDevelopmentMode(PluginWrapper pluginWrapper,
|
||||
Plugin oldPlugin) {
|
||||
if (!RuntimeMode.DEPLOYMENT.equals(pluginWrapper.getRuntimeMode())) {
|
||||
if (RuntimeMode.DEPLOYMENT.equals(pluginWrapper.getRuntimeMode())) {
|
||||
return;
|
||||
}
|
||||
YamlPluginFinder yamlPluginFinder = new YamlPluginFinder();
|
||||
|
|
|
@ -35,7 +35,7 @@ public class BasePlugin extends Plugin {
|
|||
return applicationContext;
|
||||
}
|
||||
|
||||
public HaloPluginManager getPluginManager() {
|
||||
private HaloPluginManager getPluginManager() {
|
||||
return (HaloPluginManager) getWrapper().getPluginManager();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package run.halo.app.plugin;
|
||||
|
||||
import java.util.Optional;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.pf4j.Plugin;
|
||||
import org.pf4j.PluginFactory;
|
||||
import org.pf4j.PluginWrapper;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
|
||||
/**
|
||||
* The default implementation for PluginFactory.
|
||||
* <p>Get a {@link BasePlugin} instance from the {@link PluginApplicationContext}.</p>
|
||||
*
|
||||
* @author guqing
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Slf4j
|
||||
public class BasePluginFactory implements PluginFactory {
|
||||
|
||||
@Override
|
||||
public Plugin create(PluginWrapper pluginWrapper) {
|
||||
return getPluginContext(pluginWrapper)
|
||||
.map(context -> {
|
||||
try {
|
||||
return context.getBean(BasePlugin.class);
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
log.info(
|
||||
"No bean named 'basePlugin' found in the context create default instance");
|
||||
DefaultListableBeanFactory beanFactory =
|
||||
context.getDefaultListableBeanFactory();
|
||||
BasePlugin pluginInstance = new BasePlugin(pluginWrapper);
|
||||
beanFactory.registerSingleton(Plugin.class.getName(), pluginInstance);
|
||||
return pluginInstance;
|
||||
}
|
||||
})
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private Optional<PluginApplicationContext> getPluginContext(PluginWrapper pluginWrapper) {
|
||||
try {
|
||||
return Optional.of(ExtensionContextRegistry.getInstance())
|
||||
.map(registry -> registry.getByPluginId(pluginWrapper.getPluginId()));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ import org.pf4j.ExtensionFinder;
|
|||
import org.pf4j.PluginDependency;
|
||||
import org.pf4j.PluginDescriptor;
|
||||
import org.pf4j.PluginDescriptorFinder;
|
||||
import org.pf4j.PluginFactory;
|
||||
import org.pf4j.PluginRepository;
|
||||
import org.pf4j.PluginRuntimeException;
|
||||
import org.pf4j.PluginState;
|
||||
|
@ -80,6 +81,11 @@ public class HaloPluginManager extends DefaultPluginManager
|
|||
return pluginApplicationInitializer.getPluginApplicationContext(pluginId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PluginFactory createPluginFactory() {
|
||||
return new BasePluginFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
this.pluginApplicationInitializer = new PluginApplicationInitializer(this);
|
||||
|
|
|
@ -66,6 +66,8 @@ public class PluginApplicationInitializer {
|
|||
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
|
||||
stopWatch.stop();
|
||||
|
||||
beanFactory.registerSingleton("pluginWrapper", haloPluginManager.getPlugin(pluginId));
|
||||
|
||||
populateSettingFetcher(pluginId, beanFactory);
|
||||
|
||||
log.debug("Total millis: {} ms -> {}", stopWatch.getTotalTimeMillis(),
|
||||
|
|
|
@ -50,7 +50,7 @@ public class YamlPluginDescriptorFinder implements PluginDescriptorFinder {
|
|||
DefaultPluginDescriptor defaultPluginDescriptor =
|
||||
new DefaultPluginDescriptor(pluginId,
|
||||
spec.getDescription(),
|
||||
spec.getPluginClass(),
|
||||
BasePlugin.class.getName(),
|
||||
spec.getVersion(),
|
||||
spec.getRequires(),
|
||||
spec.getAuthor(),
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.mockito.Mock;
|
|||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.pf4j.PluginState;
|
||||
import org.pf4j.PluginWrapper;
|
||||
import org.pf4j.RuntimeMode;
|
||||
import run.halo.app.core.extension.Plugin;
|
||||
import run.halo.app.extension.ExtensionClient;
|
||||
import run.halo.app.extension.controller.Reconciler;
|
||||
|
@ -53,6 +54,7 @@ class PluginReconcilerTest {
|
|||
pluginReconciler = new PluginReconciler(extensionClient, haloPluginManager, jsBundleRule);
|
||||
|
||||
when(haloPluginManager.getPlugin(any())).thenReturn(pluginWrapper);
|
||||
when(pluginWrapper.getRuntimeMode()).thenReturn(RuntimeMode.DEPLOYMENT);
|
||||
when(haloPluginManager.getUnresolvedPlugins()).thenReturn(List.of());
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ class YamlPluginFinderTest {
|
|||
}
|
||||
],
|
||||
"requires": ">=2.0.0",
|
||||
"pluginClass": "run.halo.app.plugin.BasePlugin",
|
||||
"pluginClass": null,
|
||||
"enabled": false,
|
||||
"extensionLocations": null,
|
||||
settingName: null,
|
||||
|
|
Loading…
Reference in New Issue