From b9e5ed2f4cba92aa3816c92abbddadf75083b40a Mon Sep 17 00:00:00 2001 From: guqing <38999863+guqing@users.noreply.github.com> Date: Tue, 21 Jun 2022 15:34:25 +0800 Subject: [PATCH] feat: add shared application context for plugin (#2174) * feat: add shared application context for plugin * chore: remove todo notes * fix: router function composite --- .../app/plugin/PluginApplicationContext.java | 61 ------------------ .../plugin/PluginApplicationInitializer.java | 9 ++- .../plugin/PluginCompositeRouterFunction.java | 26 ++++---- .../app/plugin/SharedApplicationContext.java | 15 +++++ .../SharedApplicationContextHolder.java | 64 +++++++++++++++++++ .../SharedApplicationContextHolderTest.java | 37 +++++++++++ 6 files changed, 137 insertions(+), 75 deletions(-) create mode 100644 src/main/java/run/halo/app/plugin/SharedApplicationContext.java create mode 100644 src/main/java/run/halo/app/plugin/SharedApplicationContextHolder.java create mode 100644 src/test/java/run/halo/app/plugin/SharedApplicationContextHolderTest.java diff --git a/src/main/java/run/halo/app/plugin/PluginApplicationContext.java b/src/main/java/run/halo/app/plugin/PluginApplicationContext.java index 108de64b8..33ae252de 100644 --- a/src/main/java/run/halo/app/plugin/PluginApplicationContext.java +++ b/src/main/java/run/halo/app/plugin/PluginApplicationContext.java @@ -1,17 +1,6 @@ package run.halo.app.plugin; -import java.lang.reflect.Field; -import java.util.Set; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.context.ApplicationEvent; -import org.springframework.context.PayloadApplicationEvent; -import org.springframework.context.event.ApplicationEventMulticaster; -import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.GenericApplicationContext; -import org.springframework.core.ResolvableType; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; /** * The generic IOC container for plugins. @@ -25,56 +14,6 @@ public class PluginApplicationContext extends GenericApplicationContext { private String pluginId; - /** - *
覆盖父类方法中判断context parent不为空时使用parent context广播事件的逻辑。 - * 如果主应用桥接事件到插件中且设置了parent会导致发布事件时死循环.
- * - * @param event the event to publish (may be an {@link ApplicationEvent} or a payload object - * to be turned into a {@link PayloadApplicationEvent}) - * @param eventType the resolved event type, if known - */ - @Override - protected void publishEvent(@NonNull Object event, @Nullable ResolvableType eventType) { - Assert.notNull(event, "Event must not be null"); - - // Decorate event as an ApplicationEvent if necessary - ApplicationEvent applicationEvent; - if (event instanceof ApplicationEvent) { - applicationEvent = (ApplicationEvent) event; - } else { - applicationEvent = new PayloadApplicationEvent<>(this, event); - if (eventType == null) { - eventType = ((PayloadApplicationEvent>) applicationEvent).getResolvableType(); - } - } - - // Multicast right now if possible - or lazily once the multicaster is initialized - SetAn {@link ApplicationContext} implementation shared by plugins.
+ *Beans in the Core that need to be shared with plugins will be injected into this + * {@link SharedApplicationContext}.
+ * + * @author guqing + * @since 2.0.0 + */ +public class SharedApplicationContext extends GenericApplicationContext { +} diff --git a/src/main/java/run/halo/app/plugin/SharedApplicationContextHolder.java b/src/main/java/run/halo/app/plugin/SharedApplicationContextHolder.java new file mode 100644 index 000000000..490013435 --- /dev/null +++ b/src/main/java/run/halo/app/plugin/SharedApplicationContextHolder.java @@ -0,0 +1,64 @@ +package run.halo.app.plugin; + +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; +import run.halo.app.extension.DefaultSchemeManager; +import run.halo.app.extension.ExtensionClient; + +/** + *This {@link SharedApplicationContextHolder} class is used to hold a singleton instance of + * {@link SharedApplicationContext}.
+ *If sharedApplicationContext cache is null when calling the {@link #getInstance()} method, + * then it will call {@link #createSharedApplicationContext()} to create and cache it. Otherwise, + * it will be obtained directly.
+ *It is thread safe.
+ * + * @author guqing + * @since 2.0.0 + */ +@Component +public class SharedApplicationContextHolder { + + private final ApplicationContext rootApplicationContext; + private volatile SharedApplicationContext sharedApplicationContext; + + public SharedApplicationContextHolder(ApplicationContext applicationContext) { + this.rootApplicationContext = applicationContext; + } + + /** + * Get singleton instance of {@link SharedApplicationContext}. + * + * @return a singleton instance of {@link SharedApplicationContext}. + */ + public SharedApplicationContext getInstance() { + if (this.sharedApplicationContext == null) { + synchronized (SharedApplicationContextHolder.class) { + if (this.sharedApplicationContext == null) { + this.sharedApplicationContext = createSharedApplicationContext(); + } + } + } + return this.sharedApplicationContext; + } + + SharedApplicationContext createSharedApplicationContext() { + // TODO Optimize creation timing + SharedApplicationContext sharedApplicationContext = new SharedApplicationContext(); + sharedApplicationContext.refresh(); + + DefaultListableBeanFactory beanFactory = + (DefaultListableBeanFactory) sharedApplicationContext.getBeanFactory(); + + // register shared object here + ExtensionClient extensionClient = rootApplicationContext.getBean(ExtensionClient.class); + beanFactory.registerSingleton("extensionClient", extensionClient); + DefaultSchemeManager defaultSchemeManager = + rootApplicationContext.getBean(DefaultSchemeManager.class); + beanFactory.registerSingleton("schemeManager", defaultSchemeManager); + // TODO add more shared instance here + + return sharedApplicationContext; + } +} diff --git a/src/test/java/run/halo/app/plugin/SharedApplicationContextHolderTest.java b/src/test/java/run/halo/app/plugin/SharedApplicationContextHolderTest.java new file mode 100644 index 000000000..0bf05ef13 --- /dev/null +++ b/src/test/java/run/halo/app/plugin/SharedApplicationContextHolderTest.java @@ -0,0 +1,37 @@ +package run.halo.app.plugin; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; + +/** + * Tests for {@link SharedApplicationContextHolder}. + * + * @author guqing + * @since 2.0.0 + */ +@SpringBootTest +@AutoConfigureTestDatabase +class SharedApplicationContextHolderTest { + + @Autowired + SharedApplicationContextHolder sharedApplicationContextHolder; + + @Test + void getInstance() { + SharedApplicationContext instance1 = sharedApplicationContextHolder.getInstance(); + SharedApplicationContext instance2 = sharedApplicationContextHolder.getInstance(); + assertThat(instance1).isNotNull(); + assertThat(instance1).isEqualTo(instance2); + } + + @Test + void createSharedApplicationContext() { + SharedApplicationContext sharedApplicationContext = + sharedApplicationContextHolder.createSharedApplicationContext(); + assertThat(sharedApplicationContext).isNotNull(); + } +} \ No newline at end of file