mirror of https://github.com/halo-dev/halo
Fix the issue with repeatedly building plugin RouterFunction for CustomEndpoints (#4890)
* fix: OOM occured when using ab to test custom endpoints provided by plugin * refactor: custom endpoints to rotuer function register for plugin * refactor: bean post processor register * Register AggregatedRouterFunction bean instead of adding bean factory post processor * Remove debug lines --------- Co-authored-by: John Niang <johnniang@foxmail.com>pull/4910/head
parent
4ee4a8fd36
commit
57a1f2ec18
|
@ -0,0 +1,38 @@
|
||||||
|
package run.halo.app.plugin;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
import org.springframework.web.reactive.function.server.HandlerFunction;
|
||||||
|
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||||
|
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||||
|
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||||
|
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
import run.halo.app.core.extension.endpoint.CustomEndpoint;
|
||||||
|
import run.halo.app.core.extension.endpoint.CustomEndpointsBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aggregated router function built from all custom endpoints.
|
||||||
|
*
|
||||||
|
* @author johnniang
|
||||||
|
*/
|
||||||
|
public class AggregatedRouterFunction implements RouterFunction<ServerResponse> {
|
||||||
|
|
||||||
|
private final RouterFunction<ServerResponse> aggregated;
|
||||||
|
|
||||||
|
public AggregatedRouterFunction(ObjectProvider<CustomEndpoint> customEndpoints) {
|
||||||
|
var builder = new CustomEndpointsBuilder();
|
||||||
|
customEndpoints.orderedStream()
|
||||||
|
.forEach(builder::add);
|
||||||
|
this.aggregated = builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<HandlerFunction<ServerResponse>> route(ServerRequest request) {
|
||||||
|
return aggregated.route(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(RouterFunctions.Visitor visitor) {
|
||||||
|
this.aggregated.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,6 +36,7 @@ import run.halo.app.infra.properties.HaloProperties;
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class PluginApplicationInitializer {
|
public class PluginApplicationInitializer {
|
||||||
|
|
||||||
protected final HaloPluginManager haloPluginManager;
|
protected final HaloPluginManager haloPluginManager;
|
||||||
|
|
||||||
private final ExtensionContextRegistry contextRegistry = ExtensionContextRegistry.getInstance();
|
private final ExtensionContextRegistry contextRegistry = ExtensionContextRegistry.getInstance();
|
||||||
|
@ -89,6 +90,8 @@ public class PluginApplicationInitializer {
|
||||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
|
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
|
||||||
stopWatch.stop();
|
stopWatch.stop();
|
||||||
|
|
||||||
|
pluginApplicationContext.registerBean(AggregatedRouterFunction.class);
|
||||||
|
|
||||||
beanFactory.registerSingleton("pluginContext", createPluginContext(plugin));
|
beanFactory.registerSingleton("pluginContext", createPluginContext(plugin));
|
||||||
// TODO deprecated
|
// TODO deprecated
|
||||||
beanFactory.registerSingleton("pluginWrapper", haloPluginManager.getPlugin(pluginId));
|
beanFactory.registerSingleton("pluginWrapper", haloPluginManager.getPlugin(pluginId));
|
||||||
|
|
|
@ -2,7 +2,7 @@ package run.halo.app.plugin;
|
||||||
|
|
||||||
import static run.halo.app.plugin.ExtensionContextRegistry.getInstance;
|
import static run.halo.app.plugin.ExtensionContextRegistry.getInstance;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import com.google.common.collect.Iterables;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.springframework.context.support.AbstractApplicationContext;
|
import org.springframework.context.support.AbstractApplicationContext;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
|
@ -14,8 +14,6 @@ import org.springframework.web.reactive.function.server.ServerRequest;
|
||||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import run.halo.app.core.extension.endpoint.CustomEndpoint;
|
|
||||||
import run.halo.app.core.extension.endpoint.CustomEndpointsBuilder;
|
|
||||||
import run.halo.app.plugin.resources.ReverseProxyRouterFunctionRegistry;
|
import run.halo.app.plugin.resources.ReverseProxyRouterFunctionRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,7 +46,7 @@ public class PluginCompositeRouterFunction implements RouterFunction<ServerRespo
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private List<RouterFunction<ServerResponse>> routerFunctions() {
|
private Iterable<RouterFunction<ServerResponse>> routerFunctions() {
|
||||||
getInstance().acquireReadLock();
|
getInstance().acquireReadLock();
|
||||||
try {
|
try {
|
||||||
List<PluginApplicationContext> contexts = getInstance().getPluginApplicationContexts()
|
List<PluginApplicationContext> contexts = getInstance().getPluginApplicationContexts()
|
||||||
|
@ -64,18 +62,7 @@ public class PluginCompositeRouterFunction implements RouterFunction<ServerRespo
|
||||||
.toList();
|
.toList();
|
||||||
var reverseProxies = reverseProxyRouterFunctionFactory.getRouterFunctions();
|
var reverseProxies = reverseProxyRouterFunctionFactory.getRouterFunctions();
|
||||||
|
|
||||||
var endpointBuilder = new CustomEndpointsBuilder();
|
return Iterables.concat(rawRouterFunctions, reverseProxies);
|
||||||
contexts.forEach(context -> context.getBeanProvider(CustomEndpoint.class)
|
|
||||||
.orderedStream()
|
|
||||||
.forEach(endpointBuilder::add));
|
|
||||||
var customEndpoint = endpointBuilder.build();
|
|
||||||
|
|
||||||
List<RouterFunction<ServerResponse>> routerFunctions =
|
|
||||||
new ArrayList<>(rawRouterFunctions.size() + reverseProxies.size() + 1);
|
|
||||||
routerFunctions.addAll(rawRouterFunctions);
|
|
||||||
routerFunctions.addAll(reverseProxies);
|
|
||||||
routerFunctions.add(customEndpoint);
|
|
||||||
return routerFunctions;
|
|
||||||
} finally {
|
} finally {
|
||||||
getInstance().releaseReadLock();
|
getInstance().releaseReadLock();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,23 @@
|
||||||
package run.halo.app.plugin.event;
|
package run.halo.app.plugin.event;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
import org.pf4j.PluginWrapper;
|
import org.pf4j.PluginWrapper;
|
||||||
import org.springframework.context.ApplicationEvent;
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This event will be published to <b>application context</b> once plugin is started.
|
* This event will be published to <b>application context</b> once plugin is started.
|
||||||
*
|
*
|
||||||
* @author guqing
|
* @author guqing
|
||||||
*/
|
*/
|
||||||
|
@Getter
|
||||||
public class HaloPluginStartedEvent extends ApplicationEvent {
|
public class HaloPluginStartedEvent extends ApplicationEvent {
|
||||||
|
|
||||||
private final PluginWrapper plugin;
|
private final PluginWrapper plugin;
|
||||||
|
|
||||||
|
|
||||||
public HaloPluginStartedEvent(Object source, PluginWrapper plugin) {
|
public HaloPluginStartedEvent(Object source, PluginWrapper plugin) {
|
||||||
super(source);
|
super(source);
|
||||||
|
Assert.notNull(plugin, "Plugin must not be null.");
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PluginWrapper getPlugin() {
|
|
||||||
return plugin;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ import org.springframework.web.reactive.function.server.support.RouterFunctionMa
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.test.StepVerifier;
|
import reactor.test.StepVerifier;
|
||||||
import run.halo.app.core.extension.endpoint.CustomEndpoint;
|
|
||||||
import run.halo.app.plugin.resources.ReverseProxyRouterFunctionRegistry;
|
import run.halo.app.plugin.resources.ReverseProxyRouterFunctionRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,9 +42,6 @@ class PluginCompositeRouterFunctionTest {
|
||||||
@Mock
|
@Mock
|
||||||
ObjectProvider<RouterFunction> rawRouterFunctionsProvider;
|
ObjectProvider<RouterFunction> rawRouterFunctionsProvider;
|
||||||
|
|
||||||
@Mock
|
|
||||||
ObjectProvider<CustomEndpoint> customEndpointsProvider;
|
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
PluginCompositeRouterFunction compositeRouterFunction;
|
PluginCompositeRouterFunction compositeRouterFunction;
|
||||||
|
|
||||||
|
@ -59,11 +55,9 @@ class PluginCompositeRouterFunctionTest {
|
||||||
ExtensionContextRegistry.getInstance().register("fake-plugin", fakeContext);
|
ExtensionContextRegistry.getInstance().register("fake-plugin", fakeContext);
|
||||||
|
|
||||||
when(rawRouterFunctionsProvider.orderedStream()).thenReturn(Stream.empty());
|
when(rawRouterFunctionsProvider.orderedStream()).thenReturn(Stream.empty());
|
||||||
when(customEndpointsProvider.orderedStream()).thenReturn(Stream.empty());
|
|
||||||
|
|
||||||
when(fakeContext.getBeanProvider(RouterFunction.class))
|
when(fakeContext.getBeanProvider(RouterFunction.class))
|
||||||
.thenReturn(rawRouterFunctionsProvider);
|
.thenReturn(rawRouterFunctionsProvider);
|
||||||
when(fakeContext.getBeanProvider(CustomEndpoint.class)).thenReturn(customEndpointsProvider);
|
|
||||||
|
|
||||||
compositeRouterFunction =
|
compositeRouterFunction =
|
||||||
new PluginCompositeRouterFunction(reverseProxyRouterFunctionRegistry);
|
new PluginCompositeRouterFunction(reverseProxyRouterFunctionRegistry);
|
||||||
|
@ -93,11 +87,10 @@ class PluginCompositeRouterFunctionTest {
|
||||||
.verify();
|
.verify();
|
||||||
|
|
||||||
verify(rawRouterFunctionsProvider).orderedStream();
|
verify(rawRouterFunctionsProvider).orderedStream();
|
||||||
verify(customEndpointsProvider).orderedStream();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServerWebExchange createExchange(String urlTemplate) {
|
private ServerWebExchange createExchange(String urlTemplate) {
|
||||||
return MockServerWebExchange.from(MockServerHttpRequest.get(urlTemplate));
|
return MockServerWebExchange.from(MockServerHttpRequest.get(urlTemplate));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue