From 03109b3115a0ff71070fc7b10a3813ec11dd8aef Mon Sep 17 00:00:00 2001 From: Linyuzai <120718461@qq.com> Date: Sat, 15 Jun 2024 17:02:00 +0800 Subject: [PATCH] plugin lock --- .../core/autoload/PluginAutoLoadEvent.java | 7 +- .../core/autoload/PluginAutoLoader.java | 2 - .../core/autoload/PluginAutoReloadEvent.java | 7 +- .../core/autoload/PluginAutoUnloadEvent.java | 7 +- .../WatchServicePluginAutoLoader.java | 70 +++---- .../location/LocalPluginLocation.java | 40 ++++ .../autoload/location/PluginLocation.java | 6 + .../plugin/core/concept/AbstractPlugin.java | 20 +- .../core/concept/AbstractPluginConcept.java | 177 +++++++----------- .../linyuzai/plugin/core/concept/Plugin.java | 18 +- .../plugin/core/concept/PluginConcept.java | 6 + .../core/exception/PluginUnloadException.java | 14 ++ .../core/extract/AbstractPluginExtractor.java | 4 +- .../plugin/core/extract/DynamicExtractor.java | 8 +- .../core/extract/PluginContextExtractor.java | 7 + .../plugin/core/lock/DefaultPluginLock.java | 52 +++++ .../linyuzai/plugin/core/lock/PluginLock.java | 14 ++ .../plugin/core/lock/PluginLockException.java | 21 +++ .../repository/DefaultPluginRepository.java | 50 +++-- .../core/repository/PluginRepository.java | 8 +- .../jar/extract/JarDynamicExtractor.java | 3 +- .../PluginConceptConfiguration.java | 18 +- .../PluginManagementConfiguration.java | 4 +- .../bean/BeanDynamicExtractor.java | 3 +- .../PluginManagementController.java | 78 +++++++- .../ReactivePluginManagementController.java | 2 +- .../ServletPluginManagementController.java | 2 +- .../resources/concept/plugin/management.html | 147 +++++++-------- 28 files changed, 513 insertions(+), 282 deletions(-) create mode 100644 concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/exception/PluginUnloadException.java create mode 100644 concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/lock/DefaultPluginLock.java create mode 100644 concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/lock/PluginLock.java create mode 100644 concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/lock/PluginLockException.java diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/PluginAutoLoadEvent.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/PluginAutoLoadEvent.java index f212df26f..7cc56019c 100644 --- a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/PluginAutoLoadEvent.java +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/PluginAutoLoadEvent.java @@ -1,13 +1,18 @@ package com.github.linyuzai.plugin.core.autoload; import com.github.linyuzai.plugin.core.concept.Plugin; +import lombok.Getter; /** * 插件自动加载事件 */ +@Getter public class PluginAutoLoadEvent extends PluginAutoEvent { - public PluginAutoLoadEvent(Plugin plugin) { + private final String path; + + public PluginAutoLoadEvent(Plugin plugin, String path) { super(plugin); + this.path = path; } } diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/PluginAutoLoader.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/PluginAutoLoader.java index 300b5f960..44353314d 100644 --- a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/PluginAutoLoader.java +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/PluginAutoLoader.java @@ -20,6 +20,4 @@ public interface PluginAutoLoader { void addGroup(String group); Boolean getGroupState(String group); - - Plugin getPlugin(String group, String name); } diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/PluginAutoReloadEvent.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/PluginAutoReloadEvent.java index 118838e49..1f91a1aa2 100644 --- a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/PluginAutoReloadEvent.java +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/PluginAutoReloadEvent.java @@ -1,13 +1,18 @@ package com.github.linyuzai.plugin.core.autoload; import com.github.linyuzai.plugin.core.concept.Plugin; +import lombok.Getter; /** * 插件自动重新加载事件 */ +@Getter public class PluginAutoReloadEvent extends PluginAutoEvent { - public PluginAutoReloadEvent(Plugin plugin) { + private final String path; + + public PluginAutoReloadEvent(Plugin plugin, String path) { super(plugin); + this.path = path; } } diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/PluginAutoUnloadEvent.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/PluginAutoUnloadEvent.java index 116a0d26e..70b8d96a8 100644 --- a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/PluginAutoUnloadEvent.java +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/PluginAutoUnloadEvent.java @@ -1,13 +1,18 @@ package com.github.linyuzai.plugin.core.autoload; import com.github.linyuzai.plugin.core.concept.Plugin; +import lombok.Getter; /** * 插件自动重新加载事件 */ +@Getter public class PluginAutoUnloadEvent extends PluginAutoEvent { - public PluginAutoUnloadEvent(Plugin plugin) { + private final String path; + + public PluginAutoUnloadEvent(Plugin plugin, String path) { super(plugin); + this.path = path; } } diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/WatchServicePluginAutoLoader.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/WatchServicePluginAutoLoader.java index 5cc089fba..595b0f0c1 100644 --- a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/WatchServicePluginAutoLoader.java +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/WatchServicePluginAutoLoader.java @@ -33,8 +33,6 @@ public class WatchServicePluginAutoLoader implements PluginAutoLoader { */ private final PluginLocation location; - private final Map pathIdMapping = new ConcurrentHashMap<>(); - private final Map watchStates = new ConcurrentHashMap<>(); private WatchService watchService; @@ -87,16 +85,6 @@ public Boolean getGroupState(String group) { return watchStates.getOrDefault(group, false); } - @Override - public Plugin getPlugin(String group, String name) { - String path = location.getLoadedPluginPath(group, name); - Object pluginId = pathIdMapping.get(path); - if (pluginId == null) { - return null; - } - return concept.getRepository().get(pluginId); - } - private void notifyOnStart(String group) { String[] names = location.getLoadedPlugins(group); for (String name : names) { @@ -158,48 +146,48 @@ public void onNotify(WatchEvent event, String group) { } public void onNotify(WatchEvent.Kind kind, String group, String name) { - String pluginPath = location.getLoadedPluginPath(group, name); - if (pluginPath == null) { + String path = location.getLoadedPluginPath(group, name); + if (path == null) { return; } if (kind == StandardWatchEventKinds.ENTRY_CREATE) { - onFileCreated(pluginPath); + onFileCreated(path); } else if (kind == StandardWatchEventKinds.ENTRY_MODIFY) { - onFileModified(pluginPath); + onFileModified(path); } else if (kind == StandardWatchEventKinds.ENTRY_DELETE) { - onFileDeleted(pluginPath); + onFileDeleted(path); } } /** * 文件创建 * - * @param pluginPath 监听到的事件 + * @param path 监听到的事件 */ - public void onFileCreated(String pluginPath) { - Plugin plugin = load(pluginPath); - concept.getEventPublisher().publish(new PluginAutoLoadEvent(plugin)); + public void onFileCreated(String path) { + Plugin plugin = load(path); + concept.getEventPublisher().publish(new PluginAutoLoadEvent(plugin, path)); } /** * 文件修改 * - * @param pluginPath 监听到的事件 + * @param path 监听到的事件 */ - public void onFileModified(String pluginPath) { - Plugin plugin = reload(pluginPath); - concept.getEventPublisher().publish(new PluginAutoReloadEvent(plugin)); + public void onFileModified(String path) { + Plugin plugin = reload(path); + concept.getEventPublisher().publish(new PluginAutoReloadEvent(plugin, path)); } /** * 文件删除 * - * @param pluginPath 监听到的事件 + * @param path 监听到的事件 */ - public void onFileDeleted(String pluginPath) { - Plugin plugin = unload(pluginPath); + public void onFileDeleted(String path) { + Plugin plugin = unload(path); if (plugin != null) { - concept.getEventPublisher().publish(new PluginAutoUnloadEvent(plugin)); + concept.getEventPublisher().publish(new PluginAutoUnloadEvent(plugin, path)); } } @@ -207,32 +195,26 @@ public void onError(Throwable e) { concept.getEventPublisher().publish(new PluginLoadErrorEvent(e)); } - public Plugin load(String pluginPath) { - Plugin plugin = concept.load(pluginPath); - pathIdMapping.put(pluginPath, plugin.getId()); - return plugin; + public Plugin load(String path) { + return concept.load(path); } /** * 卸载并移除映射关系 * - * @param pluginPath 文件路径 + * @param path 文件路径 */ - public Plugin unload(String pluginPath) { - Object id = pathIdMapping.remove(pluginPath); - if (id == null) { - return null; - } - return concept.unload(id); + public Plugin unload(String path) { + return concept.unload(path); } /** * 重新加载 * - * @param pluginPath 插件源 + * @param path 插件源 */ - public Plugin reload(String pluginPath) { - unload(pluginPath); - return load(pluginPath); + public Plugin reload(String path) { + unload(path); + return load(path); } } diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/location/LocalPluginLocation.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/location/LocalPluginLocation.java index 75013a147..90916fa71 100644 --- a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/location/LocalPluginLocation.java +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/location/LocalPluginLocation.java @@ -92,6 +92,46 @@ public String getDeletedPluginPath(String group, String name) { return getPluginPath(group, name, DELETED); } + @Override + public void load(String group, String name) { + move(group, name, UNLOADED, LOADED); + } + + @Override + public void unload(String group, String name) { + move(group, name, LOADED, UNLOADED); + } + + @Override + public void delete(String group, String name) { + move(group, name, UNLOADED, DELETED); + } + + protected boolean move(String group, String name, String from, String to) { + String fromPath = getPluginPath(group, name, from); + if (fromPath == null) { + throw new IllegalArgumentException(name + " is not a Plugin"); + } + File fromFile = new File(fromPath); + if (!fromFile.exists()) { + throw new IllegalArgumentException(name + " not existed"); + } + String toPath = getPluginPath(group, name, to); + File toFile = new File(toPath); + int i = 1; + while (toFile.exists()) { + String path = toFile.getAbsolutePath(); + int index = path.lastIndexOf("."); + if (index == -1) { + toFile = new File(path + i); + } else { + toFile = new File(path.substring(0, index) + "(" + i + ")" + path.substring(index)); + } + i++; + } + return fromFile.renameTo(toFile); + } + protected File getGroupDirectory(String group) { return check(new File(basePath, group)); } diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/location/PluginLocation.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/location/PluginLocation.java index 3fb39fff5..f95244d5b 100644 --- a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/location/PluginLocation.java +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/autoload/location/PluginLocation.java @@ -33,6 +33,12 @@ public interface PluginLocation { String getDeletedPluginPath(String group, String name); + void load(String group, String name); + + void unload(String group, String name); + + void delete(String group, String name); + interface Filter { boolean filter(String group, String name); diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/concept/AbstractPlugin.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/concept/AbstractPlugin.java index 160038f62..819f59ed3 100644 --- a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/concept/AbstractPlugin.java +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/concept/AbstractPlugin.java @@ -9,6 +9,7 @@ import java.io.IOException; import java.util.*; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -16,20 +17,34 @@ @Setter public abstract class AbstractPlugin implements Plugin { - private final Collection readers = new ArrayList<>(); + private final Collection readers = new CopyOnWriteArrayList<>(); + + private final Collection destroyListeners = new CopyOnWriteArrayList<>(); private Metadata metadata; private PluginConcept concept; + @Override public void addReader(PluginReader reader) { this.readers.add(reader); } + @Override public void removeReader(PluginReader reader) { this.readers.remove(reader); } + @Override + public void addDestroyListener(DestroyListener listener) { + this.destroyListeners.add(listener); + } + + @Override + public void removeDestroyListener(DestroyListener listener) { + this.destroyListeners.remove(listener); + } + public Collection getReaders(Class readable) { return readers.stream() .filter(it -> it.support(readable)) @@ -105,6 +120,9 @@ public void release(PluginContext context) { @Override public void destroy() { + for (DestroyListener listener : destroyListeners) { + listener.onDestroy(this); + } for (PluginReader reader : readers) { try { reader.close(); diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/concept/AbstractPluginConcept.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/concept/AbstractPluginConcept.java index d40fea9bc..7aa130798 100644 --- a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/concept/AbstractPluginConcept.java +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/concept/AbstractPluginConcept.java @@ -5,20 +5,22 @@ import com.github.linyuzai.plugin.core.event.*; import com.github.linyuzai.plugin.core.exception.PluginException; import com.github.linyuzai.plugin.core.exception.PluginLoadException; +import com.github.linyuzai.plugin.core.exception.PluginUnloadException; import com.github.linyuzai.plugin.core.extract.PluginExtractor; import com.github.linyuzai.plugin.core.factory.PluginFactory; import com.github.linyuzai.plugin.core.filter.PluginFilter; import com.github.linyuzai.plugin.core.handle.PluginHandler; import com.github.linyuzai.plugin.core.handle.PluginHandlerChain; import com.github.linyuzai.plugin.core.handle.PluginHandlerChainFactory; +import com.github.linyuzai.plugin.core.lock.PluginLock; import com.github.linyuzai.plugin.core.logger.PluginLogger; import com.github.linyuzai.plugin.core.repository.PluginRepository; import com.github.linyuzai.plugin.core.resolve.PluginResolver; import com.github.linyuzai.plugin.core.tree.PluginTree; import com.github.linyuzai.plugin.core.tree.PluginTreeFactory; import lombok.Getter; +import lombok.NonNull; import lombok.Setter; -import lombok.SneakyThrows; import java.util.*; @@ -34,6 +36,14 @@ public abstract class AbstractPluginConcept implements PluginConcept { */ protected PluginContextFactory contextFactory; + protected PluginTreeFactory treeFactory; + + protected PluginHandlerChainFactory handlerChainFactory; + + protected PluginRepository repository; + + protected PluginLock lock; + /** * 事件发布者 */ @@ -41,12 +51,6 @@ public abstract class AbstractPluginConcept implements PluginConcept { protected PluginLogger logger; - protected PluginTreeFactory treeFactory; - - protected PluginHandlerChainFactory handlerChainFactory; - - protected PluginRepository repository; - protected Collection handlers; /** @@ -74,27 +78,26 @@ public void destroy() { @Override public void addExtractors(PluginExtractor... extractors) { addExtractors(Arrays.asList(extractors)); - resetHandlerChain(); } @Override public void addExtractors(Collection extractors) { this.extractors.addAll(extractors); - + resetHandlerChain(); } @Override public void removeExtractors(PluginExtractor... extractors) { removeExtractors(Arrays.asList(extractors)); - resetHandlerChain(); } @Override public void removeExtractors(Collection extractors) { this.extractors.removeAll(extractors); + resetHandlerChain(); } - protected PluginHandlerChain getHandlerChain() { + protected PluginHandlerChain obtainHandlerChain() { if (handlerChain == null) { synchronized (this) { if (handlerChain == null) { @@ -142,7 +145,11 @@ public Plugin create(Object o, PluginContext context) { * @param o 插件源 */ @Override - public Plugin load(Object o) { + public Plugin load(@NonNull Object o) { + lock.lock(o, PluginLock.LOADING); + if (repository.contains(o)) { + throw new IllegalArgumentException("Plugin is already loaded: " + o); + } //创建上下文 PluginContext context = contextFactory.create(this); try { @@ -168,7 +175,7 @@ public Plugin load(Object o) { eventPublisher.publish(new PluginPreparedEvent(context)); //解析插件 - getHandlerChain().next(context); + obtainHandlerChain().next(context); //提取插件 for (PluginExtractor extractor : extractors) { extractor.extract(context); @@ -179,12 +186,14 @@ public Plugin load(Object o) { //销毁上下文 context.destroy(); - repository.add(plugin); + repository.add(o, plugin); eventPublisher.publish(new PluginLoadedEvent(plugin)); return plugin; } catch (Throwable e) { throw new PluginLoadException(context, e); + } finally { + lock.unlock(o, PluginLock.LOADING); } } @@ -195,13 +204,35 @@ public Plugin load(Object o) { * @param o 插件源 */ @Override - public Plugin unload(Object o) { - Plugin removed = repository.remove(o); - if (removed != null) { - removed.destroy(); - eventPublisher.publish(new PluginUnloadedEvent(removed)); + public Plugin unload(@NonNull Object o) { + lock.lock(o, PluginLock.UNLOADING); + try { + Plugin removed = repository.remove(o); + if (removed != null) { + removed.destroy(); + eventPublisher.publish(new PluginUnloadedEvent(removed)); + } + return removed; + } catch (Throwable e) { + throw new PluginUnloadException(o, e); + } finally { + lock.unlock(o, PluginLock.UNLOADING); } - return removed; + } + + @Override + public boolean isLoaded(Object o) { + return repository.contains(o); + } + + @Override + public boolean isLoading(Object o) { + return PluginLock.LOADING.equals(lock.getLockArg(o)); + } + + @Override + public boolean isUnloading(Object o) { + return PluginLock.UNLOADING.equals(lock.getLockArg(o)); } @SuppressWarnings("unchecked") @@ -209,12 +240,14 @@ public static abstract class AbstractBuilder, T protected PluginContextFactory contextFactory; - protected PluginHandlerChainFactory handlerChainFactory; - protected PluginTreeFactory treeFactory; + protected PluginHandlerChainFactory handlerChainFactory; + protected PluginRepository repository; + protected PluginLock lock; + protected PluginEventPublisher eventPublisher; protected PluginLogger logger; @@ -238,13 +271,13 @@ public B contextFactory(PluginContextFactory contextFactory) { return (B) this; } - public B handlerChainFactory(PluginHandlerChainFactory handlerChainFactory) { - this.handlerChainFactory = handlerChainFactory; + public B treeFactory(PluginTreeFactory treeFactory) { + this.treeFactory = treeFactory; return (B) this; } - public B treeFactory(PluginTreeFactory treeFactory) { - this.treeFactory = treeFactory; + public B handlerChainFactory(PluginHandlerChainFactory handlerChainFactory) { + this.handlerChainFactory = handlerChainFactory; return (B) this; } @@ -253,6 +286,11 @@ public B repository(PluginRepository repository) { return (B) this; } + public B lock(PluginLock lock) { + this.lock = lock; + return (B) this; + } + /** * 设置事件发布者 * @@ -378,10 +416,12 @@ public T build() { T concept = create(); eventPublisher.register(eventListeners); concept.setContextFactory(contextFactory); - concept.setHandlerChainFactory(handlerChainFactory); concept.setTreeFactory(treeFactory); + concept.setHandlerChainFactory(handlerChainFactory); concept.setRepository(repository); + concept.setLock(lock); concept.setEventPublisher(eventPublisher); + concept.setLogger(logger); concept.setFactories(factories); concept.setHandlers(handlers); concept.setExtractors(extractors); @@ -389,88 +429,5 @@ public T build() { } protected abstract T create(); - - /** - * 遍历插件提取器,添加插件提取器依赖的插件解析器 - * - * @param extractors 插件提取器 - */ - @Deprecated - @SneakyThrows - private void addResolversDependOnExtractors(Collection extractors) { - for (PluginExtractor extractor : extractors) { - //插件提取器依赖的插件解析器 - Class[] dependencies = extractor.getDependencies(); - for (Class dependency : dependencies) { - //已经存在 - if (containsResolver(dependency)) { - continue; - } - //获得对应的实现类 - /*Class implOrDefault = - resolverDefaultImpl.getOrDefault(dependency, dependency);*/ - //实例化 - PluginResolver resolver = (PluginResolver) dependency.newInstance(); - //添加该插件解析器依赖的解析器 - addResolversWithDependencies(Collections.singletonList(resolver)); - } - } - } - - /** - * 遍历插件解析器,添加插件解析器依赖的插件解析器。 - * - * @param resolvers 插件解析器 - */ - @Deprecated - @SneakyThrows - private void addResolversWithDependencies(Collection resolvers) { - if (resolvers.isEmpty()) { - return; - } - for (PluginResolver resolver : resolvers) { - this.handlers.add(0, resolver); - } - - Set> unfounded = new HashSet<>(); - for (PluginResolver resolver : resolvers) { - //插件解析器依赖的插件解析器 - Class[] dependencies = resolver.getDependencies(); - for (Class dependency : dependencies) { - //已经存在 - if (containsResolver(dependency)) { - continue; - } - unfounded.add(dependency); - } - } - List unfoundedPluginResolvers = new ArrayList<>(); - if (!unfounded.isEmpty()) { - //遍历需要但是还没有的插件解析器类 - for (Class dependency : unfounded) { - //获得对应的实现类 - //实例化 - PluginResolver instance = (PluginResolver) dependency.newInstance(); - unfoundedPluginResolvers.add(instance); - } - //添加这些新实例化的插件解析器依赖的插件解析器 - addResolversWithDependencies(unfoundedPluginResolvers); - } - } - - /** - * 目标插件解析器类是否已经存在 - * - * @param target 目标插件解析器类 - * @return 如果已经存在返回 true 否则返回 false - */ - private boolean containsResolver(Class target) { - for (PluginHandler resolver : handlers) { - if (target.isInstance(resolver)) { - return true; - } - } - return false; - } } } diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/concept/Plugin.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/concept/Plugin.java index 2401d069d..6c21c96db 100644 --- a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/concept/Plugin.java +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/concept/Plugin.java @@ -1,6 +1,7 @@ package com.github.linyuzai.plugin.core.concept; import com.github.linyuzai.plugin.core.context.PluginContext; +import com.github.linyuzai.plugin.core.read.PluginReader; import java.io.IOException; import java.io.InputStream; @@ -12,8 +13,6 @@ public interface Plugin { Object getId(); - T read(Class readable, Object key); - Metadata getMetadata(); void setMetadata(Metadata metadata); @@ -22,6 +21,16 @@ public interface Plugin { void setConcept(PluginConcept concept); + void addReader(PluginReader reader); + + void removeReader(PluginReader reader); + + void addDestroyListener(DestroyListener listener); + + void removeDestroyListener(DestroyListener listener); + + T read(Class readable, Object key); + void initialize(); void destroy(); @@ -81,4 +90,9 @@ interface Content { InputStream getInputStream() throws IOException; } + + interface DestroyListener { + + void onDestroy(Plugin plugin); + } } diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/concept/PluginConcept.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/concept/PluginConcept.java index bed82e999..e425eb369 100644 --- a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/concept/PluginConcept.java +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/concept/PluginConcept.java @@ -48,6 +48,12 @@ public interface PluginConcept { */ Plugin unload(Object o); + boolean isLoaded(Object o); + + boolean isLoading(Object o); + + boolean isUnloading(Object o); + /** * 获得插件存储 * diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/exception/PluginUnloadException.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/exception/PluginUnloadException.java new file mode 100644 index 000000000..3cf926a21 --- /dev/null +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/exception/PluginUnloadException.java @@ -0,0 +1,14 @@ +package com.github.linyuzai.plugin.core.exception; + +import lombok.Getter; + +@Getter +public class PluginUnloadException extends PluginException { + + private final Object plugin; + + public PluginUnloadException(Object plugin, Throwable cause) { + super(cause); + this.plugin = plugin; + } +} diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/extract/AbstractPluginExtractor.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/extract/AbstractPluginExtractor.java index f5b2258d4..ede49f9f8 100644 --- a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/extract/AbstractPluginExtractor.java +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/extract/AbstractPluginExtractor.java @@ -118,7 +118,7 @@ public void extract(PluginContext context) { if (invoke == null) { return; } - onExtract((T) invoke); + onExtract((T) invoke, context); context.publish(new PluginExtractedEvent(context, this, invoke)); } @@ -127,7 +127,7 @@ public void extract(PluginContext context) { * * @param plugin 插件对象 */ - public abstract void onExtract(T plugin); + public abstract void onExtract(T plugin, PluginContext context); /** * 依赖的解析器 {@link PluginResolver} diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/extract/DynamicExtractor.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/extract/DynamicExtractor.java index 5ae8e8ab3..49ea82ed1 100644 --- a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/extract/DynamicExtractor.java +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/extract/DynamicExtractor.java @@ -154,7 +154,7 @@ public Annotation[] getAnnotations() { } @Override - public void onExtract(PluginContext plugin) { + public void onExtract(PluginContext context) { } }.getInvoker(); @@ -184,7 +184,7 @@ public Annotation[] getAnnotations() { } @Override - public void onExtract(Plugin plugin) { + public void onExtract(Plugin plugin, PluginContext context) { } }.getInvoker(); @@ -214,7 +214,7 @@ public Annotation[] getAnnotations() { } @Override - public void onExtract(Void plugin) { + public void onExtract(Void plugin, PluginContext context) { } }.getInvoker(); @@ -244,7 +244,7 @@ public Annotation[] getAnnotations() { } @Override - public void onExtract(Void plugin) { + public void onExtract(Void plugin, PluginContext context) { } }.getInvoker(); diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/extract/PluginContextExtractor.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/extract/PluginContextExtractor.java index 1d5e410f4..7005e3c1e 100644 --- a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/extract/PluginContextExtractor.java +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/extract/PluginContextExtractor.java @@ -34,4 +34,11 @@ public PluginMatcher getMatcher(Type type, Annotation[] annotations) { } return null; } + + @Override + public void onExtract(T plugin, PluginContext context) { + onExtract(plugin); + } + + public abstract void onExtract(T context); } diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/lock/DefaultPluginLock.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/lock/DefaultPluginLock.java new file mode 100644 index 000000000..ba39a64d9 --- /dev/null +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/lock/DefaultPluginLock.java @@ -0,0 +1,52 @@ +package com.github.linyuzai.plugin.core.lock; + +import lombok.Getter; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; + +public class DefaultPluginLock implements PluginLock { + + private final Map lockMap = new ConcurrentHashMap<>(); + + @Override + public void lock(Object o, Object arg) { + LockObject lock = lockMap.computeIfAbsent(o, key -> new LockObject()); + if (lock.tryLock()) { + lock.arg = arg; + return; + } + throw new PluginLockException(o, lock.arg, arg); + } + + @Override + public void unlock(Object o, Object arg) { + LockObject lock = lockMap.remove(o); + if (lock == null) { + return; + } + lock.unlock(); + } + + @Override + public Object getLockArg(Object o) { + System.out.println(lockMap); + LockObject lock = lockMap.get(o); + if (lock == null) { + return null; + } + return lock.arg; + } + + @Getter + public static class LockObject extends ReentrantLock { + + private volatile Object arg; + + @Override + public String toString() { + return String.valueOf(arg); + } + } +} diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/lock/PluginLock.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/lock/PluginLock.java new file mode 100644 index 000000000..c62467142 --- /dev/null +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/lock/PluginLock.java @@ -0,0 +1,14 @@ +package com.github.linyuzai.plugin.core.lock; + +public interface PluginLock { + + String LOADING = "LOADING"; + + String UNLOADING = "UNLOADING"; + + void lock(Object o, Object arg); + + void unlock(Object o, Object arg); + + Object getLockArg(Object o); +} diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/lock/PluginLockException.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/lock/PluginLockException.java new file mode 100644 index 000000000..089d3db7b --- /dev/null +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/lock/PluginLockException.java @@ -0,0 +1,21 @@ +package com.github.linyuzai.plugin.core.lock; + +import com.github.linyuzai.plugin.core.exception.PluginException; +import lombok.Getter; + +@Getter +public class PluginLockException extends PluginException { + + private final Object plugin; + + private final Object current; + + private final Object request; + + protected PluginLockException(Object plugin, Object current, Object request) { + super("Plugin lock failure: " + plugin); + this.plugin = plugin; + this.current = current; + this.request = request; + } +} diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/repository/DefaultPluginRepository.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/repository/DefaultPluginRepository.java index d593befef..ebe262699 100644 --- a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/repository/DefaultPluginRepository.java +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/repository/DefaultPluginRepository.java @@ -2,8 +2,11 @@ import com.github.linyuzai.plugin.core.concept.Plugin; +import java.util.Iterator; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; import java.util.stream.Stream; public class DefaultPluginRepository implements PluginRepository { @@ -11,34 +14,51 @@ public class DefaultPluginRepository implements PluginRepository { private final Map plugins = new ConcurrentHashMap<>(); @Override - public Plugin get(Object id) { - return plugins.get(id); + public Plugin get(Object o) { + Plugin plugin = plugins.get(o); + if (plugin != null) { + return plugin; + } + for (Plugin value : plugins.values()) { + if (Objects.equals(o, value.getId())) { + return value; + } + } + return null; } @Override - public void add(Plugin plugin) { + public void add(Object o, Plugin plugin) { if (plugin == null) { return; } - plugins.put(plugin.getId(), plugin); + plugins.put(o, plugin); } @Override - public Plugin remove(Object plugin) { - if (plugin instanceof Plugin) { - return plugins.remove(((Plugin) plugin).getId()); - } else { - return plugins.remove(plugin); + public Plugin remove(Object o) { + Plugin plugin = plugins.remove(o); + if (plugin != null) { + return plugin; } + Iterator iterator = plugins.values().iterator(); + while (iterator.hasNext()) { + Plugin next = iterator.next(); + if (Objects.equals(next.getId(), o) || Objects.equals(next, o)) { + iterator.remove(); + return next; + } + } + return null; } @Override - public boolean contains(Object plugin) { - if (plugin instanceof Plugin) { - return plugins.containsValue(plugin); - } else { - return plugins.containsKey(plugin); - } + public boolean contains(Object o) { + return plugins.containsKey(o) || plugins.values() + .stream() + .map(Plugin::getId) + .collect(Collectors.toSet()).contains(o) || + (o instanceof Plugin && plugins.containsValue(o)); } @Override diff --git a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/repository/PluginRepository.java b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/repository/PluginRepository.java index 995232974..44fc045dd 100644 --- a/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/repository/PluginRepository.java +++ b/concept-plugin/concept-plugin-core/src/main/java/com/github/linyuzai/plugin/core/repository/PluginRepository.java @@ -6,13 +6,13 @@ public interface PluginRepository { - Plugin get(Object id); + Plugin get(Object o); - void add(Plugin plugin); + void add(Object o, Plugin plugin); - Plugin remove(Object plugin); + Plugin remove(Object o); - boolean contains(Object plugin); + boolean contains(Object o); Stream stream(); } diff --git a/concept-plugin/concept-plugin-jar/src/main/java/com/github/linyuzai/plugin/jar/extract/JarDynamicExtractor.java b/concept-plugin/concept-plugin-jar/src/main/java/com/github/linyuzai/plugin/jar/extract/JarDynamicExtractor.java index 69c9656c8..0f140e46f 100644 --- a/concept-plugin/concept-plugin-jar/src/main/java/com/github/linyuzai/plugin/jar/extract/JarDynamicExtractor.java +++ b/concept-plugin/concept-plugin-jar/src/main/java/com/github/linyuzai/plugin/jar/extract/JarDynamicExtractor.java @@ -1,5 +1,6 @@ package com.github.linyuzai.plugin.jar.extract; +import com.github.linyuzai.plugin.core.context.PluginContext; import com.github.linyuzai.plugin.core.extract.DynamicExtractor; import com.github.linyuzai.plugin.jar.match.PluginAnnotation; import com.github.linyuzai.plugin.jar.match.PluginClass; @@ -93,7 +94,7 @@ public Annotation[] getAnnotations() { } @Override - public void onExtract(Void plugin) { + public void onExtract(Void plugin, PluginContext context) { } }.getInvoker(); diff --git a/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/PluginConceptConfiguration.java b/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/PluginConceptConfiguration.java index f69b1e32e..61b1c47bb 100644 --- a/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/PluginConceptConfiguration.java +++ b/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/PluginConceptConfiguration.java @@ -20,6 +20,8 @@ import com.github.linyuzai.plugin.core.filter.PluginFilter; import com.github.linyuzai.plugin.core.handle.DefaultPluginHandlerChainFactory; import com.github.linyuzai.plugin.core.handle.PluginHandlerChainFactory; +import com.github.linyuzai.plugin.core.lock.DefaultPluginLock; +import com.github.linyuzai.plugin.core.lock.PluginLock; import com.github.linyuzai.plugin.core.logger.PluginErrorLogger; import com.github.linyuzai.plugin.core.logger.PluginLoadLogger; import com.github.linyuzai.plugin.core.logger.PluginLogger; @@ -90,14 +92,14 @@ public PluginContextFactory pluginContextFactory() { @Bean @ConditionalOnMissingBean - public PluginHandlerChainFactory pluginHandlerChainFactory() { - return new DefaultPluginHandlerChainFactory(); + public PluginTreeFactory pluginTreeFactory() { + return new DefaultPluginTreeFactory(); } @Bean @ConditionalOnMissingBean - public PluginTreeFactory pluginTreeFactory() { - return new DefaultPluginTreeFactory(); + public PluginHandlerChainFactory pluginHandlerChainFactory() { + return new DefaultPluginHandlerChainFactory(); } @Bean @@ -106,6 +108,12 @@ public PluginRepository pluginRepository() { return new DefaultPluginRepository(); } + @Bean + @ConditionalOnMissingBean + public PluginLock pluginLock() { + return new DefaultPluginLock(); + } + @Bean @ConditionalOnMissingBean public PluginEventPublisher pluginEventPublisher(ApplicationEventPublisher eventPublisher) { @@ -149,6 +157,7 @@ public PluginConcept pluginConcept(PluginContextFactory contextFactory, PluginHandlerChainFactory handlerChainFactory, PluginTreeFactory treeFactory, PluginRepository repository, + PluginLock lock, PluginEventPublisher eventPublisher, PluginLogger logger, List factories, @@ -161,6 +170,7 @@ public PluginConcept pluginConcept(PluginContextFactory contextFactory, .handlerChainFactory(handlerChainFactory) .treeFactory(treeFactory) .repository(repository) + .lock(lock) .eventPublisher(eventPublisher) .logger(logger) .addFactories(factories) diff --git a/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/PluginManagementConfiguration.java b/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/PluginManagementConfiguration.java index 6b722a09e..c01e12519 100644 --- a/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/PluginManagementConfiguration.java +++ b/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/PluginManagementConfiguration.java @@ -18,7 +18,7 @@ public class PluginManagementConfiguration { @Configuration(proxyBeanMethods = false) public static class WebMvcConfiguration implements WebMvcConfigurer { - @Bean + @Bean(initMethod = "init") public ServletPluginManagementController servletPluginManagementController() { return new ServletPluginManagementController(); } @@ -37,7 +37,7 @@ public void addResourceHandlers(org.springframework.web.servlet.config.annotatio @Configuration(proxyBeanMethods = false) public static class WebFluxConfiguration implements WebFluxConfigurer { - @Bean + @Bean(initMethod = "init") public ReactivePluginManagementController reactivePluginManagementController() { return new ReactivePluginManagementController(); } diff --git a/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/bean/BeanDynamicExtractor.java b/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/bean/BeanDynamicExtractor.java index 781237678..05fec85a7 100644 --- a/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/bean/BeanDynamicExtractor.java +++ b/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/bean/BeanDynamicExtractor.java @@ -1,5 +1,6 @@ package com.github.linyuzai.plugin.autoconfigure.bean; +import com.github.linyuzai.plugin.core.context.PluginContext; import com.github.linyuzai.plugin.jar.extract.JarDynamicExtractor; import lombok.Getter; import org.springframework.context.ApplicationContext; @@ -47,7 +48,7 @@ public Annotation[] getAnnotations() { } @Override - public void onExtract(Void plugin) { + public void onExtract(Void plugin, PluginContext context) { } }.getInvoker(); diff --git a/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/management/PluginManagementController.java b/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/management/PluginManagementController.java index a4a700a79..7be076b2c 100644 --- a/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/management/PluginManagementController.java +++ b/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/management/PluginManagementController.java @@ -1,8 +1,13 @@ package com.github.linyuzai.plugin.autoconfigure.management; +import com.github.linyuzai.plugin.core.autoload.PluginAutoLoadEvent; import com.github.linyuzai.plugin.core.autoload.PluginAutoLoader; +import com.github.linyuzai.plugin.core.autoload.PluginAutoReloadEvent; +import com.github.linyuzai.plugin.core.autoload.PluginAutoUnloadEvent; import com.github.linyuzai.plugin.core.autoload.location.PluginLocation; import com.github.linyuzai.plugin.core.concept.Plugin; +import com.github.linyuzai.plugin.core.concept.PluginConcept; +import com.github.linyuzai.plugin.core.event.PluginEventListener; import lombok.Data; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -10,13 +15,9 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -24,12 +25,51 @@ public class PluginManagementController { protected final Log log = LogFactory.getLog("PluginManagement"); + protected final Set loadingSet = Collections.newSetFromMap(new ConcurrentHashMap<>()); + + protected final Set unloadingSet = Collections.newSetFromMap(new ConcurrentHashMap<>()); + + @Autowired + protected PluginConcept concept; + @Autowired protected PluginLocation location; @Autowired protected PluginAutoLoader loader; + public void init() { + concept.getEventPublisher().register(new PluginAutoLoadListener()); + } + + @GetMapping("load") + public Response load(@RequestParam("group") String group, @RequestParam("name") String name) { + return manage(() -> { + String path = location.getLoadedPluginPath(group, name); + loadingSet.add(path); + location.load(group, name); + return null; + }, () -> "加载失败"); + } + + @GetMapping("unload") + public Response unload(@RequestParam("group") String group, @RequestParam("name") String name) { + return manage(() -> { + String path = location.getLoadedPluginPath(group, name); + unloadingSet.add(path); + location.unload(group, name); + return null; + }, () -> "卸载失败"); + } + + @GetMapping("delete") + public Response delete(@RequestParam("group") String group, @RequestParam("name") String name) { + return manage(() -> { + location.delete(group, name); + return null; + }, () -> "删除失败"); + } + @GetMapping("groups") public Response groups() { return manage(() -> { @@ -71,8 +111,12 @@ public ManagedGroup group(String group) { } public ManagedPlugin loadedPlugin(String group, String plugin) { - Plugin get = loader.getPlugin(group, plugin); + String path = location.getLoadedPluginPath(group, plugin); + Plugin get = concept.getRepository().get(path); if (get == null) { + if (loadingSet.contains(path)) { + return new ManagedPlugin(plugin, "", "loading"); + } return new ManagedPlugin(plugin, "", "error"); } else { String name = get.getMetadata().get(Plugin.Metadata.KEY_NAME, ""); @@ -81,6 +125,10 @@ public ManagedPlugin loadedPlugin(String group, String plugin) { } public ManagedPlugin unloadedPlugin(String group, String plugin) { + String path = location.getLoadedPluginPath(group, plugin); + if (unloadingSet.contains(path)) { + return new ManagedPlugin(plugin, "", "unloading"); + } return new ManagedPlugin(plugin, "", "unloaded"); } @@ -96,6 +144,22 @@ public Response failure(String message) { return new Response(false, message); } + public class PluginAutoLoadListener implements PluginEventListener { + + @Override + public void onEvent(Object event) { + if (event instanceof PluginAutoLoadEvent) { + loadingSet.remove(((PluginAutoLoadEvent) event).getPath()); + } else if (event instanceof PluginAutoReloadEvent) { + + } else if (event instanceof PluginAutoUnloadEvent) { + unloadingSet.remove(((PluginAutoUnloadEvent) event).getPath()); + } else { + + } + } + } + @Getter @RequiredArgsConstructor public static class ManagedGroup { diff --git a/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/management/ReactivePluginManagementController.java b/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/management/ReactivePluginManagementController.java index d711183fb..ddbb22b01 100644 --- a/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/management/ReactivePluginManagementController.java +++ b/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/management/ReactivePluginManagementController.java @@ -15,7 +15,7 @@ public class ReactivePluginManagementController extends PluginManagementControll public Mono upload(@RequestPart("file") Flux files, @RequestPart("group") String group) { return files.flatMap(it -> { String filename = it.filename(); - String path = location.getLoadedPluginPath(group, filename); + String path = location.getUnloadedPluginPath(group, filename); return it.transferTo(new File(path)); }).collectList().then(); } diff --git a/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/management/ServletPluginManagementController.java b/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/management/ServletPluginManagementController.java index 3ec41f50d..ce7dc4313 100644 --- a/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/management/ServletPluginManagementController.java +++ b/concept-plugin/concept-plugin-spring-boot-starter/src/main/java/com/github/linyuzai/plugin/autoconfigure/management/ServletPluginManagementController.java @@ -17,7 +17,7 @@ public class ServletPluginManagementController extends PluginManagementControlle public void upload(@RequestParam("file") MultipartFile[] files, @RequestParam("group") String group) throws IOException { for (MultipartFile file : files) { String filename = file.getOriginalFilename(); - String path = location.getLoadedPluginPath(group, filename); + String path = location.getUnloadedPluginPath(group, filename); file.transferTo(new File(path)); } } diff --git a/concept-plugin/concept-plugin-spring-boot-starter/src/main/resources/concept/plugin/management.html b/concept-plugin/concept-plugin-spring-boot-starter/src/main/resources/concept/plugin/management.html index 29849f7c5..5c9cb7663 100644 --- a/concept-plugin/concept-plugin-spring-boot-starter/src/main/resources/concept/plugin/management.html +++ b/concept-plugin/concept-plugin-spring-boot-starter/src/main/resources/concept/plugin/management.html @@ -20,7 +20,7 @@ height: 100%; } - .el-table::before { + .el-table::before, .el-table__fixed-right::before, .el-table__fixed::before { height: 0; } @@ -111,113 +111,62 @@ + :on-error="uploadError" + :data="{group: this.group}"> + - - + - - + + - + - - + + - + + - + @@ -324,6 +273,48 @@ } }); }, + uploadError(err, file, fileList) { + this.$notify.error({ + title: '插件上传', + message: '上传失败', + position: 'bottom-right' + }); + console.log(err); + }, + loadPlugin(name) { + this.$http.get('/concept-plugin/management/load?group=' + this.group + '&name=' + name) + .then((response) => { + let body = response.body; + if (body.success) { + this.refreshPlugins(); + } else { + console.log(response); + } + }); + }, + unloadPlugin(name) { + this.$http.get('/concept-plugin/management/unload?group=' + this.group + '&name=' + name) + .then((response) => { + let body = response.body; + if (body.success) { + this.refreshPlugins(); + } else { + console.log(response); + } + }); + }, + deletePlugin(name) { + this.$http.get('/concept-plugin/management/delete?group=' + this.group + '&name=' + name) + .then((response) => { + let body = response.body; + if (body.success) { + this.refreshPlugins(); + } else { + console.log(response); + } + }); + }, + explain() { let content = "本产品主要用于多人开发时提高接口调试效率
" +