Skip to content

Commit d6fd59c

Browse files
committed
switch thread context loader to plugin class loader when calling plugin lifecycle methods
1 parent 7a3264e commit d6fd59c

File tree

7 files changed

+115
-28
lines changed

7 files changed

+115
-28
lines changed

bifromq-plugin/bifromq-plugin-archetype/src/main/resources/archetype-resources/plugin-build/src/main/java/__pluginName__.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
/*
2+
* Copyright (c) 2024. The BifroMQ Authors. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
* Unless required by applicable law or agreed to in writing,
9+
* software distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and limitations under the License.
12+
*/
13+
114
package ${groupId};
215

316
import ch.qos.logback.classic.LoggerContext;
@@ -33,6 +46,14 @@ public class ${pluginName} extends BifroMQPlugin<${pluginContextName}> {
3346
}
3447
}
3548

49+
protected void doStart() {
50+
log.info("TODO: Start your plugin");
51+
}
52+
53+
protected void doStop() {
54+
log.info("TODO: Stop your plugin");
55+
}
56+
3657
private void configureLoggerContext(Path rootPath) {
3758
try {
3859
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();

bifromq-plugin/bifromq-plugin-context/src/main/java/com/baidu/bifromq/plugin/BifroMQPluginDescriptor.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,24 @@
2626
public class BifroMQPluginDescriptor {
2727
private final PluginDescriptor descriptor;
2828
private final Path pluginRoot;
29+
private final ClassLoader pluginClassLoader;
2930
private final boolean isDevelopment;
3031

3132
/**
3233
* Constructor of BifroMQPluginContext.
3334
*
3435
* @param descriptor the descriptor of the plugin
3536
* @param pluginRoot the root path of the plugin
37+
* @param classLoader the plugin specific classloader
3638
* @param isDevelopment the runtime mode
3739
*/
38-
public BifroMQPluginDescriptor(PluginDescriptor descriptor, Path pluginRoot, boolean isDevelopment) {
40+
public BifroMQPluginDescriptor(PluginDescriptor descriptor,
41+
Path pluginRoot,
42+
ClassLoader classLoader,
43+
boolean isDevelopment) {
3944
this.descriptor = descriptor;
4045
this.pluginRoot = pluginRoot;
46+
this.pluginClassLoader = classLoader;
4147
this.isDevelopment = isDevelopment;
4248
}
4349
}

bifromq-plugin/bifromq-plugin-main/src/main/java/com/baidu/bifromq/plugin/BifroMQPlugin.java

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,17 +94,50 @@ public C context() {
9494
* Starts the plugin. This method is called when the plugin is loaded. It initializes the plugin context.
9595
*/
9696
@Override
97-
public void start() {
98-
super.start();
99-
context.init();
97+
public final void start() {
98+
ClassLoader origClassLoader = Thread.currentThread().getContextClassLoader();
99+
try {
100+
Thread.currentThread().setContextClassLoader(descriptor.getPluginClassLoader());
101+
super.start();
102+
context.init();
103+
doStart();
104+
} finally {
105+
Thread.currentThread().setContextClassLoader(origClassLoader);
106+
}
107+
}
108+
109+
/**
110+
* Subclasses can override this method to perform additional initialization when the plugin is started.
111+
*/
112+
protected void doStart() {
113+
100114
}
101115

102116
/**
103117
* Stops the plugin. This method is called when the plugin is unloaded. It cleans up the plugin context.
104118
*/
105119
@Override
106-
public void stop() {
107-
super.stop();
108-
context.close();
120+
public final void stop() {
121+
ClassLoader origClassLoader = Thread.currentThread().getContextClassLoader();
122+
try {
123+
Thread.currentThread().setContextClassLoader(descriptor.getPluginClassLoader());
124+
doStop();
125+
context.close();
126+
super.stop();
127+
} finally {
128+
Thread.currentThread().setContextClassLoader(origClassLoader);
129+
}
130+
}
131+
132+
/**
133+
* Subclasses can override this method to perform additional cleanup when the plugin is stopped.
134+
*/
135+
protected void doStop() {
136+
137+
}
138+
139+
@Override
140+
public final void delete() {
141+
super.delete();
109142
}
110143
}

bifromq-plugin/bifromq-plugin-manager/src/main/java/com/baidu/bifromq/plugin/manager/BifroMQExtensionFactory.java

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,27 @@
1+
/*
2+
* Copyright (c) 2024. The BifroMQ Authors. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
* Unless required by applicable law or agreed to in writing,
9+
* software distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and limitations under the License.
12+
*/
13+
114
package com.baidu.bifromq.plugin.manager;
215

316
import com.baidu.bifromq.plugin.BifroMQPlugin;
17+
import com.baidu.bifromq.plugin.BifroMQPluginContext;
18+
import java.lang.reflect.Constructor;
419
import lombok.extern.slf4j.Slf4j;
520
import org.pf4j.DefaultExtensionFactory;
621
import org.pf4j.Plugin;
722
import org.pf4j.PluginManager;
823
import org.pf4j.PluginRuntimeException;
924

10-
import java.lang.reflect.Constructor;
11-
1225
@Slf4j
1326
public class BifroMQExtensionFactory extends DefaultExtensionFactory {
1427
private final PluginManager pluginManager;
@@ -23,22 +36,24 @@ public <T> T create(Class<T> extensionClass) {
2336
Thread.currentThread().setContextClassLoader(extensionClass.getClassLoader());
2437
Plugin ownerPlugin = pluginManager.whichPlugin(extensionClass).getPlugin();
2538
if (ownerPlugin instanceof BifroMQPlugin) {
26-
return createExtensionWithContext(extensionClass, (BifroMQPlugin<?>) ownerPlugin);
39+
return createExtensionWithContext(extensionClass,
40+
(BifroMQPlugin<? extends BifroMQPluginContext>) ownerPlugin);
2741
}
2842
return super.create(extensionClass);
2943
} finally {
3044
Thread.currentThread().setContextClassLoader(originalLoader);
3145
}
3246
}
3347

34-
private <T> T createExtensionWithContext(Class<T> extensionClass, BifroMQPlugin<?> ownerPlugin) {
48+
private <T, C extends BifroMQPluginContext> T createExtensionWithContext(Class<T> extensionClass,
49+
BifroMQPlugin<C> ownerPlugin) {
3550
try {
36-
Object pluginContext = ownerPlugin.context();
51+
C pluginContext = ownerPlugin.context();
3752
Constructor<T> constructor = extensionClass.getConstructor(pluginContext.getClass());
3853
return constructor.newInstance(pluginContext);
3954
} catch (NoSuchMethodException e) {
4055
log.debug("No constructor with plugin context found for extension[{}], fallback to no-arg constructor",
41-
extensionClass.getName());
56+
extensionClass.getName());
4257
return super.create(extensionClass);
4358
} catch (Throwable e) {
4459
throw new PluginRuntimeException(e);

bifromq-plugin/bifromq-plugin-manager/src/main/java/com/baidu/bifromq/plugin/manager/BifroMQPluginFactory.java

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,28 @@
1+
/*
2+
* Copyright (c) 2024. The BifroMQ Authors. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
* Unless required by applicable law or agreed to in writing,
9+
* software distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and limitations under the License.
12+
*/
13+
114
package com.baidu.bifromq.plugin.manager;
215

16+
import static org.pf4j.RuntimeMode.DEVELOPMENT;
17+
318
import com.baidu.bifromq.plugin.BifroMQPlugin;
419
import com.baidu.bifromq.plugin.BifroMQPluginDescriptor;
20+
import java.lang.reflect.Constructor;
521
import lombok.extern.slf4j.Slf4j;
622
import org.pf4j.DefaultPluginFactory;
723
import org.pf4j.Plugin;
824
import org.pf4j.PluginWrapper;
925

10-
import java.lang.reflect.Constructor;
11-
12-
import static org.pf4j.RuntimeMode.DEVELOPMENT;
13-
1426
@Slf4j
1527
public class BifroMQPluginFactory extends DefaultPluginFactory {
1628
protected Plugin createInstance(Class<?> pluginClass, PluginWrapper pluginWrapper) {
@@ -28,9 +40,10 @@ protected Plugin createInstance(Class<?> pluginClass, PluginWrapper pluginWrappe
2840

2941
private Plugin createBifroMQPluginInstance(Class<?> pluginClass, PluginWrapper pluginWrapper) {
3042
BifroMQPluginDescriptor context = new BifroMQPluginDescriptor(
31-
pluginWrapper.getDescriptor(),
32-
pluginWrapper.getPluginPath(),
33-
pluginWrapper.getRuntimeMode() == DEVELOPMENT);
43+
pluginWrapper.getDescriptor(),
44+
pluginWrapper.getPluginPath(),
45+
pluginWrapper.getPluginClassLoader(),
46+
pluginWrapper.getRuntimeMode() == DEVELOPMENT);
3447
try {
3548
Constructor<?> constructor = pluginClass.getDeclaredConstructor(BifroMQPluginDescriptor.class);
3649
return (Plugin) constructor.newInstance(context);

bifromq-plugin/bifromq-plugin-setting-provider-helper/src/main/java/com/baidu/bifromq/plugin/settingprovider/SettingProviderManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ public <R> R provide(Setting setting, String tenantId) {
6060
@Override
6161
public void close() {
6262
if (stopped.compareAndSet(false, true)) {
63-
log.info("Closing setting provider manager");
63+
log.debug("Closing setting provider manager");
6464
provider.close();
65-
log.info("Setting provider manager closed");
65+
log.debug("Setting provider manager closed");
6666
}
6767
}
6868
}

build/build-plugin-demo/src/main/java/com/baidu/demo/plugin/DemoPlugin.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,11 @@
2222
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
2323
import io.micrometer.prometheus.PrometheusConfig;
2424
import io.micrometer.prometheus.PrometheusMeterRegistry;
25-
import lombok.extern.slf4j.Slf4j;
26-
2725
import java.io.IOException;
2826
import java.io.OutputStream;
2927
import java.net.InetSocketAddress;
3028
import java.time.Duration;
29+
import lombok.extern.slf4j.Slf4j;
3130

3231
@Slf4j
3332
public class DemoPlugin extends BifroMQPlugin<DemoPluginContext> {
@@ -63,8 +62,8 @@ public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticC
6362
// }
6463
}
6564
return DistributionStatisticConfig.builder()
66-
.expiry(Duration.ofSeconds(5))
67-
.build().merge(config);
65+
.expiry(Duration.ofSeconds(5))
66+
.build().merge(config);
6867
}
6968
});
7069
Metrics.addRegistry(registry);
@@ -84,13 +83,13 @@ public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticC
8483
}
8584

8685
@Override
87-
public void start() {
86+
protected void doStart() {
8887
serverThread.start();
8988
log.debug("Prometheus exporter started");
9089
}
9190

9291
@Override
93-
public void stop() {
92+
protected void doStop() {
9493
prometheusExportServer.stop(0);
9594
Metrics.removeRegistry(registry);
9695
log.debug("Prometheus exporter stopped");

0 commit comments

Comments
 (0)