mirror of https://github.com/longtai-cn/hippo4j
Support automatic registration of plugins and plugin registrars (#914)
* feat: Support to centralized management of all plugins * feat: Support automatic registration of plugins and plugin registrarspull/916/head
parent
2604336725
commit
328bb4a47f
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.core.plugin.manager;
|
||||
|
||||
import cn.hippo4j.core.plugin.ThreadPoolPlugin;
|
||||
import lombok.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link GlobalThreadPoolPluginManager}.
|
||||
*/
|
||||
public class DefaultGlobalThreadPoolPluginManager implements GlobalThreadPoolPluginManager {
|
||||
|
||||
/**
|
||||
* enable thread pool plugins
|
||||
*/
|
||||
private final Map<String, ThreadPoolPlugin> enableThreadPoolPlugins = new ConcurrentHashMap<>(8);
|
||||
|
||||
/**
|
||||
* enable thread pool plugin registrars
|
||||
*/
|
||||
private final Map<String, ThreadPoolPluginRegistrar> enableThreadPoolPluginRegistrars = new ConcurrentHashMap<>(8);
|
||||
|
||||
/**
|
||||
* registered supports
|
||||
*/
|
||||
private final Map<String, ThreadPoolPluginSupport> managedThreadPoolPluginSupports = new ConcurrentHashMap<>(32);
|
||||
|
||||
/**
|
||||
* Synchronize all enabled plugins and registrars in the current manager to the {@link ThreadPoolPluginSupport}
|
||||
* <b>whether the support has been managed by the current manager</b>.
|
||||
* After that, the support will <b>not</b> be synchronized with the plug-in and registrar states in the manager.
|
||||
*
|
||||
* @param support thread pool plugin manager delegate
|
||||
* @see #registerThreadPoolPluginSupport
|
||||
*/
|
||||
@Override
|
||||
public void doRegister(@NonNull ThreadPoolPluginSupport support) {
|
||||
enableThreadPoolPluginRegistrars.values().forEach(registrar -> registrar.doRegister(support));
|
||||
enableThreadPoolPlugins.values().forEach(support::tryRegister);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize all enabled plugins and registrars
|
||||
* in the current manager to the {@link ThreadPoolPluginSupport} <b>if the support has not been managed before</b>,
|
||||
* After that, this support will be synchronized with the plug-in and registrar status in the manager.
|
||||
*
|
||||
* @param support thread pool plugin manager support
|
||||
* @return true if the support has not been managed before, false otherwise
|
||||
* @see #doRegister
|
||||
*/
|
||||
@Override
|
||||
public boolean registerThreadPoolPluginSupport(@NonNull ThreadPoolPluginSupport support) {
|
||||
if (!managedThreadPoolPluginSupports.containsKey(support.getThreadPoolId())) {
|
||||
enableThreadPoolPluginRegistrars.values().forEach(registrar -> registrar.doRegister(support));
|
||||
enableThreadPoolPlugins.values().forEach(support::tryRegister);
|
||||
managedThreadPoolPluginSupports.put(support.getThreadPoolId(), support);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the management of the specified {@link ThreadPoolPluginSupport}.
|
||||
*
|
||||
* @param threadPoolId thread pool id
|
||||
* @return {@link ThreadPoolPluginSupport}
|
||||
*/
|
||||
@Override
|
||||
public ThreadPoolPluginSupport cancelManagement(String threadPoolId) {
|
||||
return managedThreadPoolPluginSupports.remove(threadPoolId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get registered {@link ThreadPoolPluginSupport}.
|
||||
*
|
||||
* @param threadPoolId thread-pool id
|
||||
* @return cn.hippo4j.core.plugin.manager.ThreadPoolPluginManager
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public ThreadPoolPluginSupport getManagedThreadPoolPluginSupport(String threadPoolId) {
|
||||
return managedThreadPoolPluginSupports.get(threadPoolId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all registered {@link ThreadPoolPluginSupport}
|
||||
*
|
||||
* @return all registered {@link ThreadPoolPluginSupport}
|
||||
*/
|
||||
@Override
|
||||
public Collection<ThreadPoolPluginSupport> getAllManagedThreadPoolPluginSupports() {
|
||||
return managedThreadPoolPluginSupports.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable plugin for all {@link ThreadPoolPluginSupport},
|
||||
* after action, newly registered support will also get this plugin.
|
||||
*
|
||||
* @param plugin plugin
|
||||
* @return true if the plugin has not been enabled before, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean enableThreadPoolPlugin(@NonNull ThreadPoolPlugin plugin) {
|
||||
if (Objects.isNull(enableThreadPoolPlugins.put(plugin.getId(), plugin))) {
|
||||
managedThreadPoolPluginSupports.values().forEach(support -> support.register(plugin));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all enable {@link ThreadPoolPlugin}.
|
||||
*
|
||||
* @return all published {@link ThreadPoolPlugin}
|
||||
*/
|
||||
@Override
|
||||
public Collection<ThreadPoolPlugin> getAllEnableThreadPoolPlugins() {
|
||||
return enableThreadPoolPlugins.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable {@link ThreadPoolPlugin} for all {@link ThreadPoolPluginSupport},
|
||||
* after action, newly registered support will not get this registrar.
|
||||
*
|
||||
* @param pluginId plugin id
|
||||
* @return {@link ThreadPoolPlugin} if enable, null otherwise
|
||||
*/
|
||||
@Override
|
||||
public ThreadPoolPlugin disableThreadPoolPlugin(String pluginId) {
|
||||
ThreadPoolPlugin removed = enableThreadPoolPlugins.remove(pluginId);
|
||||
if (Objects.nonNull(removed)) {
|
||||
managedThreadPoolPluginSupports.values().forEach(support -> support.unregister(pluginId));
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable registrar, then apply to all registered {@link ThreadPoolPluginSupport},
|
||||
* after action, newly registered support will also get this registrar.
|
||||
*
|
||||
* @param registrar registrar
|
||||
* @return true if the registrar has not been enabled before, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean enableThreadPoolPluginRegistrar(@NonNull ThreadPoolPluginRegistrar registrar) {
|
||||
if (Objects.isNull(enableThreadPoolPluginRegistrars.put(registrar.getId(), registrar))) {
|
||||
managedThreadPoolPluginSupports.values().forEach(registrar::doRegister);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all enable {@link ThreadPoolPluginRegistrar}.
|
||||
*
|
||||
* @return all {@link ThreadPoolPluginRegistrar}.
|
||||
*/
|
||||
@Override
|
||||
public Collection<ThreadPoolPluginRegistrar> getAllEnableThreadPoolPluginRegistrar() {
|
||||
return enableThreadPoolPluginRegistrars.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unable {@link ThreadPoolPluginRegistrar}, newly registered support will not get this registrar.
|
||||
*
|
||||
* @param registrarId registrar id
|
||||
* @return {@link ThreadPoolPluginRegistrar} if enable, null otherwise
|
||||
*/
|
||||
@Override
|
||||
public ThreadPoolPluginRegistrar disableThreadPoolPluginRegistrar(String registrarId) {
|
||||
return enableThreadPoolPluginRegistrars.remove(registrarId);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.core.plugin.manager;
|
||||
|
||||
import cn.hippo4j.core.plugin.ThreadPoolPlugin;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A globally {@link ThreadPoolPluginManager}.
|
||||
* It is used to manage {@link ThreadPoolPluginSupport} in the global,
|
||||
* so that all managed {@link ThreadPoolPluginSupport} can be registered incrementally.
|
||||
*/
|
||||
public interface GlobalThreadPoolPluginManager extends ThreadPoolPluginRegistrar {
|
||||
|
||||
/**
|
||||
* Synchronize all enabled plugins and registrars
|
||||
* in the current manager to the {@link ThreadPoolPluginSupport}.
|
||||
* After that, the support will <b>not</b> be synchronized with the plug-in and registrar states in the manager.
|
||||
*
|
||||
* @param support thread pool plugin manager delegate
|
||||
* @see #registerThreadPoolPluginSupport
|
||||
*/
|
||||
@Override
|
||||
void doRegister(ThreadPoolPluginSupport support);
|
||||
|
||||
/**
|
||||
* Synchronize all enabled plugins and registrars
|
||||
* in the current manager to the {@link ThreadPoolPluginSupport},
|
||||
* After that, this support will be synchronized with the plug-in and registrar status in the manager.
|
||||
*
|
||||
* @param support thread pool plugin manager support
|
||||
* @return true if the support has not been managed before, false otherwise
|
||||
* @see #doRegister
|
||||
*/
|
||||
boolean registerThreadPoolPluginSupport(ThreadPoolPluginSupport support);
|
||||
|
||||
/**
|
||||
* Cancel the management of the specified {@link ThreadPoolPluginSupport}.
|
||||
*
|
||||
* @param threadPoolId thread pool id
|
||||
* @return {@link ThreadPoolPluginSupport} if managed, null otherwise
|
||||
*/
|
||||
ThreadPoolPluginSupport cancelManagement(String threadPoolId);
|
||||
|
||||
/**
|
||||
* Get registered {@link ThreadPoolPluginSupport}.
|
||||
*
|
||||
* @param threadPoolId thread-pool id
|
||||
* @return {@link ThreadPoolPluginSupport} if managed, null otherwise
|
||||
*/
|
||||
ThreadPoolPluginSupport getManagedThreadPoolPluginSupport(String threadPoolId);
|
||||
|
||||
/**
|
||||
* Get all registered {@link ThreadPoolPluginSupport}
|
||||
*
|
||||
* @return all registered {@link ThreadPoolPluginSupport}
|
||||
*/
|
||||
Collection<ThreadPoolPluginSupport> getAllManagedThreadPoolPluginSupports();
|
||||
|
||||
// ===================== plugin =====================
|
||||
|
||||
/**
|
||||
* Enable plugin for all {@link ThreadPoolPluginSupport},
|
||||
* after action, newly registered support will also get this plugin.
|
||||
*
|
||||
* @param plugin plugin
|
||||
* @return true if the plugin has not been enabled before, false otherwise
|
||||
*/
|
||||
boolean enableThreadPoolPlugin(ThreadPoolPlugin plugin);
|
||||
|
||||
/**
|
||||
* Get all enable {@link ThreadPoolPlugin}.
|
||||
*
|
||||
* @return all published {@link ThreadPoolPlugin}
|
||||
*/
|
||||
Collection<ThreadPoolPlugin> getAllEnableThreadPoolPlugins();
|
||||
|
||||
/**
|
||||
* Disable {@link ThreadPoolPlugin} for all {@link ThreadPoolPluginSupport},
|
||||
* after action, newly registered support will not get this registrar.
|
||||
*
|
||||
* @param pluginId plugin id
|
||||
* @return {@link ThreadPoolPlugin} if enable, null otherwise
|
||||
*/
|
||||
ThreadPoolPlugin disableThreadPoolPlugin(String pluginId);
|
||||
|
||||
/**
|
||||
* Get all plugins from registered {@link ThreadPoolPluginSupport}.
|
||||
*
|
||||
* @return plugins
|
||||
*/
|
||||
default Collection<ThreadPoolPlugin> getAllPluginsFromManagers() {
|
||||
return getAllManagedThreadPoolPluginSupports().stream()
|
||||
.map(ThreadPoolPluginSupport::getAllPlugins)
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugins of type from registered {@link ThreadPoolPluginSupport}.
|
||||
*
|
||||
* @param pluginType plugin type
|
||||
* @return plugins
|
||||
*/
|
||||
default <A extends ThreadPoolPlugin> Collection<A> getPluginsOfTypeFromManagers(Class<A> pluginType) {
|
||||
return getAllPluginsFromManagers().stream()
|
||||
.filter(pluginType::isInstance)
|
||||
.map(pluginType::cast)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugins by id from registered {@link ThreadPoolPluginSupport}.
|
||||
*
|
||||
* @param pluginId plugin id
|
||||
* @return plugins
|
||||
*/
|
||||
default Collection<ThreadPoolPlugin> getPluginsFromManagers(String pluginId) {
|
||||
return getAllManagedThreadPoolPluginSupports().stream()
|
||||
.map(manager -> manager.getPlugin(pluginId))
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister for all registered Managers
|
||||
*
|
||||
* @param pluginId plugin id
|
||||
*/
|
||||
default void unregisterForAllManagers(String pluginId) {
|
||||
getAllManagedThreadPoolPluginSupports().forEach(s -> s.unregister(pluginId));
|
||||
}
|
||||
|
||||
// ===================== registrar =====================
|
||||
|
||||
/**
|
||||
* Enable registrar, then apply to all registered {@link ThreadPoolPluginSupport},
|
||||
* after action, newly registered support will also get this registrar.
|
||||
*
|
||||
* @param registrar registrar
|
||||
* @return true if the registrar has not been enabled before, false otherwise
|
||||
*/
|
||||
boolean enableThreadPoolPluginRegistrar(ThreadPoolPluginRegistrar registrar);
|
||||
|
||||
/**
|
||||
* Get all enable {@link ThreadPoolPluginRegistrar}.
|
||||
*
|
||||
* @return all {@link ThreadPoolPluginRegistrar}.
|
||||
*/
|
||||
Collection<ThreadPoolPluginRegistrar> getAllEnableThreadPoolPluginRegistrar();
|
||||
|
||||
/**
|
||||
* Unable {@link ThreadPoolPluginRegistrar}, newly registered support will not get this registrar.
|
||||
*
|
||||
* @param registrarId registrar id
|
||||
* @return {@link ThreadPoolPluginRegistrar} if enable, null otherwise
|
||||
*/
|
||||
ThreadPoolPluginRegistrar disableThreadPoolPluginRegistrar(String registrarId);
|
||||
|
||||
}
|
@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.core.plugin.manager;
|
||||
|
||||
import cn.hippo4j.core.plugin.ThreadPoolPlugin;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* test for {@link DefaultGlobalThreadPoolPluginManager}
|
||||
*/
|
||||
public class DefaultGlobalThreadPoolPluginManagerTest {
|
||||
|
||||
@Test
|
||||
public void testDoRegister() {
|
||||
GlobalThreadPoolPluginManager manager = new DefaultGlobalThreadPoolPluginManager();
|
||||
manager.enableThreadPoolPlugin(new TestPlugin("1"));
|
||||
manager.enableThreadPoolPlugin(new TestPlugin("2"));
|
||||
manager.enableThreadPoolPluginRegistrar(new TestRegistrar("1"));
|
||||
|
||||
TestSupport support = new TestSupport("1");
|
||||
manager.doRegister(support);
|
||||
Assert.assertEquals(3, support.getAllPlugins().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterThreadPoolPluginSupport() {
|
||||
GlobalThreadPoolPluginManager manager = new DefaultGlobalThreadPoolPluginManager();
|
||||
Assert.assertTrue(manager.enableThreadPoolPlugin(new TestPlugin("1")));
|
||||
|
||||
TestSupport support = new TestSupport("1");
|
||||
Assert.assertTrue(manager.registerThreadPoolPluginSupport(support));
|
||||
Assert.assertFalse(manager.registerThreadPoolPluginSupport(support));
|
||||
Assert.assertEquals(1, support.getAllPlugins().size());
|
||||
|
||||
// incremental update
|
||||
manager.enableThreadPoolPlugin(new TestPlugin("2"));
|
||||
manager.enableThreadPoolPluginRegistrar(new TestRegistrar("1"));
|
||||
Assert.assertEquals(3, support.getAllPlugins().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelManagement() {
|
||||
GlobalThreadPoolPluginManager manager = new DefaultGlobalThreadPoolPluginManager();
|
||||
manager.enableThreadPoolPlugin(new TestPlugin("1"));
|
||||
|
||||
TestSupport support = new TestSupport("1");
|
||||
manager.registerThreadPoolPluginSupport(support);
|
||||
Assert.assertEquals(1, support.getAllPlugins().size());
|
||||
|
||||
manager.cancelManagement(support.getThreadPoolId());
|
||||
manager.enableThreadPoolPlugin(new TestPlugin("2"));
|
||||
Assert.assertEquals(1, support.getAllPlugins().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetManagedThreadPoolPluginSupport() {
|
||||
GlobalThreadPoolPluginManager manager = new DefaultGlobalThreadPoolPluginManager();
|
||||
|
||||
TestSupport support = new TestSupport("1");
|
||||
manager.registerThreadPoolPluginSupport(support);
|
||||
Assert.assertSame(support, manager.getManagedThreadPoolPluginSupport(support.getThreadPoolId()));
|
||||
|
||||
support = new TestSupport("2");
|
||||
manager.registerThreadPoolPluginSupport(support);
|
||||
Assert.assertSame(support, manager.getManagedThreadPoolPluginSupport(support.getThreadPoolId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllManagedThreadPoolPluginSupports() {
|
||||
GlobalThreadPoolPluginManager manager = new DefaultGlobalThreadPoolPluginManager();
|
||||
manager.registerThreadPoolPluginSupport(new TestSupport("1"));
|
||||
manager.registerThreadPoolPluginSupport(new TestSupport("2"));
|
||||
Assert.assertEquals(2, manager.getAllManagedThreadPoolPluginSupports().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnableThreadPoolPlugin() {
|
||||
GlobalThreadPoolPluginManager manager = new DefaultGlobalThreadPoolPluginManager();
|
||||
TestSupport support1 = new TestSupport("1");
|
||||
manager.registerThreadPoolPluginSupport(support1);
|
||||
TestSupport support2 = new TestSupport("2");
|
||||
manager.registerThreadPoolPluginSupport(support2);
|
||||
|
||||
Assert.assertTrue(manager.enableThreadPoolPlugin(new TestPlugin("1")));
|
||||
Assert.assertFalse(manager.enableThreadPoolPlugin(new TestPlugin("1")));
|
||||
Assert.assertEquals(1, support1.getAllPlugins().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllEnableThreadPoolPlugins() {
|
||||
GlobalThreadPoolPluginManager manager = new DefaultGlobalThreadPoolPluginManager();
|
||||
manager.enableThreadPoolPlugin(new TestPlugin("1"));
|
||||
manager.enableThreadPoolPlugin(new TestPlugin("2"));
|
||||
Assert.assertEquals(2, manager.getAllEnableThreadPoolPlugins().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisableThreadPoolPlugin() {
|
||||
GlobalThreadPoolPluginManager manager = new DefaultGlobalThreadPoolPluginManager();
|
||||
manager.enableThreadPoolPlugin(new TestPlugin("1"));
|
||||
manager.enableThreadPoolPlugin(new TestPlugin("2"));
|
||||
manager.disableThreadPoolPlugin("2");
|
||||
Assert.assertEquals(1, manager.getAllEnableThreadPoolPlugins().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnableThreadPoolPluginRegistrar() {
|
||||
GlobalThreadPoolPluginManager manager = new DefaultGlobalThreadPoolPluginManager();
|
||||
Assert.assertTrue(manager.enableThreadPoolPluginRegistrar(new TestRegistrar("1")));
|
||||
Assert.assertFalse(manager.enableThreadPoolPluginRegistrar(new TestRegistrar("1")));
|
||||
Assert.assertEquals(1, manager.getAllEnableThreadPoolPluginRegistrar().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllEnableThreadPoolPluginRegistrar() {
|
||||
GlobalThreadPoolPluginManager manager = new DefaultGlobalThreadPoolPluginManager();
|
||||
manager.enableThreadPoolPluginRegistrar(new TestRegistrar("1"));
|
||||
manager.enableThreadPoolPluginRegistrar(new TestRegistrar("2"));
|
||||
Assert.assertEquals(2, manager.getAllEnableThreadPoolPluginRegistrar().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisableThreadPoolPluginRegistrar() {
|
||||
GlobalThreadPoolPluginManager manager = new DefaultGlobalThreadPoolPluginManager();
|
||||
manager.enableThreadPoolPluginRegistrar(new TestRegistrar("1"));
|
||||
manager.enableThreadPoolPluginRegistrar(new TestRegistrar("2"));
|
||||
manager.disableThreadPoolPluginRegistrar("2");
|
||||
Assert.assertEquals(1, manager.getAllEnableThreadPoolPluginRegistrar().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllPluginsFromManagers() {
|
||||
GlobalThreadPoolPluginManager manager = new DefaultGlobalThreadPoolPluginManager();
|
||||
manager.enableThreadPoolPluginRegistrar(new TestRegistrar("1"));
|
||||
manager.enableThreadPoolPlugin(new TestPlugin("1"));
|
||||
|
||||
TestSupport support1 = new TestSupport("1");
|
||||
manager.registerThreadPoolPluginSupport(support1);
|
||||
TestSupport support2 = new TestSupport("2");
|
||||
manager.registerThreadPoolPluginSupport(support2);
|
||||
|
||||
Assert.assertEquals(4, manager.getAllPluginsFromManagers().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPluginsOfTypeFromManagers() {
|
||||
GlobalThreadPoolPluginManager manager = new DefaultGlobalThreadPoolPluginManager();
|
||||
manager.enableThreadPoolPluginRegistrar(new TestRegistrar("1"));
|
||||
manager.enableThreadPoolPlugin(new TestPlugin("1"));
|
||||
|
||||
TestSupport support1 = new TestSupport("1");
|
||||
manager.registerThreadPoolPluginSupport(support1);
|
||||
TestSupport support2 = new TestSupport("2");
|
||||
manager.registerThreadPoolPluginSupport(support2);
|
||||
|
||||
Assert.assertEquals(4, manager.getPluginsOfTypeFromManagers(TestPlugin.class).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPluginsFromManagers() {
|
||||
GlobalThreadPoolPluginManager manager = new DefaultGlobalThreadPoolPluginManager();
|
||||
manager.enableThreadPoolPluginRegistrar(new TestRegistrar("1"));
|
||||
manager.enableThreadPoolPlugin(new TestPlugin("1"));
|
||||
|
||||
TestSupport support1 = new TestSupport("1");
|
||||
manager.registerThreadPoolPluginSupport(support1);
|
||||
TestSupport support2 = new TestSupport("2");
|
||||
manager.registerThreadPoolPluginSupport(support2);
|
||||
|
||||
Assert.assertEquals(2, manager.getPluginsFromManagers("1").size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnregisterForAllManagers() {
|
||||
GlobalThreadPoolPluginManager manager = new DefaultGlobalThreadPoolPluginManager();
|
||||
manager.enableThreadPoolPluginRegistrar(new TestRegistrar("1"));
|
||||
manager.enableThreadPoolPlugin(new TestPlugin("1"));
|
||||
|
||||
TestSupport support1 = new TestSupport("1");
|
||||
manager.registerThreadPoolPluginSupport(support1);
|
||||
TestSupport support2 = new TestSupport("2");
|
||||
manager.registerThreadPoolPluginSupport(support2);
|
||||
|
||||
manager.unregisterForAllManagers("1");
|
||||
Assert.assertEquals(2, manager.getAllPluginsFromManagers().size());
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
private static class TestSupport implements ThreadPoolPluginSupport {
|
||||
|
||||
private final String threadPoolId;
|
||||
private final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
|
||||
private final ThreadPoolPluginManager threadPoolPluginManager = new DefaultThreadPoolPluginManager();
|
||||
}
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
private static class TestRegistrar implements ThreadPoolPluginRegistrar {
|
||||
|
||||
private final String id;
|
||||
@Override
|
||||
public void doRegister(ThreadPoolPluginSupport support) {
|
||||
support.register(new TestPlugin("TestRegistrar"));
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
private static class TestPlugin implements ThreadPoolPlugin {
|
||||
|
||||
private final String id;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.springboot.starter.support;
|
||||
|
||||
import cn.hippo4j.common.toolkit.Assert;
|
||||
import cn.hippo4j.core.plugin.ThreadPoolPlugin;
|
||||
import cn.hippo4j.core.plugin.manager.DefaultGlobalThreadPoolPluginManager;
|
||||
import cn.hippo4j.core.plugin.manager.GlobalThreadPoolPluginManager;
|
||||
import cn.hippo4j.core.plugin.manager.ThreadPoolPluginRegistrar;
|
||||
import cn.hippo4j.core.plugin.manager.ThreadPoolPluginSupport;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.aop.framework.autoproxy.AutoProxyUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanInitializationException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationContextException;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>The extension implementation of {@link GlobalThreadPoolPluginManager} and {@link BeanPostProcessor},
|
||||
* used to register {@link ThreadPoolPlugin} for the bean initialization stage of the {@link ThreadPoolPluginSupport}.
|
||||
*
|
||||
* <p><b>NOTE:</b>
|
||||
* If the {@link ThreadPoolPlugin}, {@link ThreadPoolPluginRegistrar}, and {@link ThreadPoolPluginSupport} is set to lazy load,
|
||||
* The processor will not perceive the bean unless the user actively triggers the initialization of the bean.
|
||||
*
|
||||
* @see ThreadPoolPluginSupport
|
||||
* @see ThreadPoolPluginRegistrar
|
||||
* @see ThreadPoolPlugin
|
||||
* @see GlobalThreadPoolPluginManager
|
||||
* @see DefaultGlobalThreadPoolPluginManager
|
||||
*/
|
||||
@Slf4j
|
||||
public class ThreadPoolPluginRegisterPostProcessor extends DefaultGlobalThreadPoolPluginManager implements BeanPostProcessor, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* application context
|
||||
*/
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
/**
|
||||
* <p>Post process bean, if bean is instance of {@link ThreadPoolPlugin},
|
||||
* {@link ThreadPoolPluginRegistrar} or {@link ThreadPoolPluginSupport},
|
||||
* then take beans as an available component and register to {@link GlobalThreadPoolPluginManager}.
|
||||
*
|
||||
* @param bean the new bean instance
|
||||
* @param beanName the name of the bean
|
||||
* @return the bean instance to use, either the original or a wrapped one;
|
||||
* if {@code null}, no subsequent BeanPostProcessors will be invoked
|
||||
* @throws BeansException in case of errors
|
||||
* @see GlobalThreadPoolPluginManager#enableThreadPoolPlugin
|
||||
* @see GlobalThreadPoolPluginManager#enableThreadPoolPluginRegistrar
|
||||
* @see GlobalThreadPoolPluginManager#registerThreadPoolPluginSupport
|
||||
*/
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
Class<?> beanType = null;
|
||||
try {
|
||||
beanType = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
|
||||
} catch (NoSuchBeanDefinitionException ex) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
|
||||
}
|
||||
}
|
||||
if (Objects.isNull(beanType)) {
|
||||
log.warn("cannot resolve type for bean [{}]", beanName);
|
||||
return bean;
|
||||
}
|
||||
|
||||
// register bean if necessary
|
||||
registerThreadPoolPluginRegistrarIfNecessary(bean, beanType);
|
||||
registerThreadPoolPluginIfNecessary(bean, beanType);
|
||||
registerThreadPoolPluginSupportIfNecessary(bean, beanType);
|
||||
return bean;
|
||||
}
|
||||
|
||||
private void registerThreadPoolPluginSupportIfNecessary(Object bean, Class<?> beanType) {
|
||||
if (ThreadPoolPluginSupport.class.isAssignableFrom(beanType)) {
|
||||
ThreadPoolPluginSupport support = (ThreadPoolPluginSupport)bean;
|
||||
if (registerThreadPoolPluginSupport(support) && log.isDebugEnabled()) {
|
||||
log.info("register ThreadPoolPluginSupport [{}]", support.getThreadPoolId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerThreadPoolPluginIfNecessary(Object bean, Class<?> beanType) {
|
||||
if (ThreadPoolPlugin.class.isAssignableFrom(beanType)) {
|
||||
ThreadPoolPlugin plugin = (ThreadPoolPlugin)bean;
|
||||
if (enableThreadPoolPlugin(plugin) && log.isDebugEnabled()) {
|
||||
log.info("register ThreadPoolPlugin [{}]", plugin.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerThreadPoolPluginRegistrarIfNecessary(Object bean, Class<?> beanType) {
|
||||
if (ThreadPoolPluginRegistrar.class.isAssignableFrom(beanType)) {
|
||||
ThreadPoolPluginRegistrar registrar = (ThreadPoolPluginRegistrar)bean;
|
||||
if (enableThreadPoolPluginRegistrar(registrar) && log.isDebugEnabled()) {
|
||||
log.info("register ThreadPoolPluginRegistrar [{}]", registrar.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ApplicationContext that this object runs in.
|
||||
* Normally this call will be used to initialize the object.
|
||||
* <p>Invoked after population of normal bean properties but before an init callback such
|
||||
* as {@link InitializingBean#afterPropertiesSet()}
|
||||
* or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
|
||||
* {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
|
||||
* {@link MessageSourceAware}, if applicable.
|
||||
*
|
||||
* @param applicationContext the ApplicationContext object to be used by this object
|
||||
* @throws ApplicationContextException in case of context initialization errors
|
||||
* @throws BeansException if thrown by application context methods
|
||||
* @see BeanInitializationException
|
||||
*/
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
|
||||
Assert.isTrue(
|
||||
factory instanceof ConfigurableListableBeanFactory,
|
||||
"factory cannot cast to ConfigurableListableBeanFactory");
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) factory;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in new issue