diff --git a/application/src/main/java/run/halo/app/plugin/BeanPostProcessorUtils.java b/application/src/main/java/run/halo/app/plugin/BeanPostProcessorUtils.java new file mode 100644 index 00000000000..f29cfc24ba8 --- /dev/null +++ b/application/src/main/java/run/halo/app/plugin/BeanPostProcessorUtils.java @@ -0,0 +1,50 @@ +package run.halo.app.plugin; + +import lombok.experimental.UtilityClass; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.lang.Nullable; + +/** + * Utility class that allows for convenient registration of common bean post-processors for + * {@link PluginApplicationContext}. + * + * @author guqing + * @since 2.11.0 + */ +@UtilityClass +public class BeanPostProcessorUtils { + + public static final String CUSTOM_ENDPOINT_PROCESSOR_BEAN_NAME = + "run.halo.app.plugin.pluginCustomEndpointBeanFactoryPostProcessor"; + + /** + * Register all relevant annotation post-processors in the given registry. + * + * @param registry the registry to operate on + */ + public static void registerBeanPostProcessors(BeanDefinitionRegistry registry) { + registerBeanPostProcessors(registry, null); + } + + /** + * Register all relevant annotation post-processors in the given registry. + * + * @param registry the registry to operate on + * @param source the configuration source element (already extracted) + * that this registration was triggered from. May be {@code null} + */ + public static void registerBeanPostProcessors( + BeanDefinitionRegistry registry, @Nullable Object source) { + + if (!registry.containsBeanDefinition(CUSTOM_ENDPOINT_PROCESSOR_BEAN_NAME)) { + RootBeanDefinition def = new RootBeanDefinition( + PluginCustomEndpointBeanFactoryPostProcessor.class); + def.setSource(source); + def.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + registry.registerBeanDefinition(CUSTOM_ENDPOINT_PROCESSOR_BEAN_NAME, def); + } + // add more post processors + } +} diff --git a/application/src/main/java/run/halo/app/plugin/PluginApplicationInitializer.java b/application/src/main/java/run/halo/app/plugin/PluginApplicationInitializer.java index 45c9d367f63..39c1b16efab 100644 --- a/application/src/main/java/run/halo/app/plugin/PluginApplicationInitializer.java +++ b/application/src/main/java/run/halo/app/plugin/PluginApplicationInitializer.java @@ -36,6 +36,8 @@ */ @Slf4j public class PluginApplicationInitializer { + + protected final HaloPluginManager haloPluginManager; private final ExtensionContextRegistry contextRegistry = ExtensionContextRegistry.getInstance(); @@ -89,6 +91,8 @@ private PluginApplicationContext createPluginApplicationContext(String pluginId) AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory); stopWatch.stop(); + BeanPostProcessorUtils.registerBeanPostProcessors(beanFactory); + beanFactory.registerSingleton("pluginContext", createPluginContext(plugin)); // TODO deprecated beanFactory.registerSingleton("pluginWrapper", haloPluginManager.getPlugin(pluginId)); diff --git a/application/src/main/java/run/halo/app/plugin/PluginCustomEndpointBeanFactoryPostProcessor.java b/application/src/main/java/run/halo/app/plugin/PluginCustomEndpointBeanFactoryPostProcessor.java new file mode 100644 index 00000000000..141bdd7c478 --- /dev/null +++ b/application/src/main/java/run/halo/app/plugin/PluginCustomEndpointBeanFactoryPostProcessor.java @@ -0,0 +1,34 @@ +package run.halo.app.plugin; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.lang.NonNull; +import org.springframework.web.reactive.function.server.RouterFunction; +import run.halo.app.core.extension.endpoint.CustomEndpoint; +import run.halo.app.core.extension.endpoint.CustomEndpointsBuilder; + +/** + *

A {@link CustomEndpoint} initialization {@link BeanFactoryPostProcessor} to build + * {@link RouterFunction}s to bean factory.

+ * + * @author guqing + * @since 2.11.0 + */ +public class PluginCustomEndpointBeanFactoryPostProcessor implements BeanFactoryPostProcessor { + + @Override + public void postProcessBeanFactory(@NonNull ConfigurableListableBeanFactory beanFactory) + throws BeansException { + String[] customEndpointBeans = beanFactory.getBeanNamesForType(CustomEndpoint.class); + if (customEndpointBeans.length == 0) { + return; + } + CustomEndpointsBuilder endpointBuilder = new CustomEndpointsBuilder(); + for (String beanName : customEndpointBeans) { + CustomEndpoint customEndpoint = (CustomEndpoint) beanFactory.getBean(beanName); + endpointBuilder.add(customEndpoint); + } + beanFactory.registerSingleton("pluginCustomEndpointRouter", endpointBuilder.build()); + } +} diff --git a/application/src/main/java/run/halo/app/plugin/PluginCustomEndpointInitialization.java b/application/src/main/java/run/halo/app/plugin/PluginCustomEndpointInitialization.java deleted file mode 100644 index df05dfaddf1..00000000000 --- a/application/src/main/java/run/halo/app/plugin/PluginCustomEndpointInitialization.java +++ /dev/null @@ -1,43 +0,0 @@ -package run.halo.app.plugin; - -import lombok.RequiredArgsConstructor; -import org.springframework.context.event.EventListener; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Component; -import org.springframework.web.reactive.function.server.RouterFunction; -import run.halo.app.core.extension.endpoint.CustomEndpoint; -import run.halo.app.core.extension.endpoint.CustomEndpointsBuilder; -import run.halo.app.plugin.event.HaloPluginStartedEvent; - -/** - *

An Initialization class for plugin's {@link RouterFunction}.

- * - * @author guqing - * @since 2.11.0 - */ -@Component -@RequiredArgsConstructor -public class PluginCustomEndpointInitialization { - - private final HaloPluginManager haloPluginManager; - - /** - * Get all {@link CustomEndpoint} beans from plugin's {@link PluginApplicationContext} and - * create a {@link RouterFunction} for them to register to the bean factory on plugin startup. - */ - @Async - @EventListener(HaloPluginStartedEvent.class) - public void onPluginStartUp(HaloPluginStartedEvent event) { - var pluginName = event.getPlugin().getPluginId(); - var applicationContext = haloPluginManager.getPluginApplicationContext(pluginName); - - var endpoints = applicationContext.getBeansOfType(CustomEndpoint.class).values(); - if (endpoints.isEmpty()) { - return; - } - var endpointBuilder = new CustomEndpointsBuilder(); - endpoints.forEach(endpointBuilder::add); - applicationContext.registerBean("pluginCustomEndpointRouter", - RouterFunction.class, endpointBuilder::build); - } -}