feat(plugin): delete redundant dependencies of convert and fix version number acquisition rules

This commit is contained in:
qianmoQ 2024-11-23 04:40:41 +08:00
parent 5297c22fca
commit c7cda15d42
12 changed files with 143 additions and 42 deletions

View File

@ -25,6 +25,7 @@
<dependency>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap-convert-spi</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>

View File

@ -25,6 +25,7 @@
<dependency>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap-convert-spi</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>

View File

@ -25,6 +25,7 @@
<dependency>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap-convert-spi</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>

View File

@ -25,6 +25,7 @@
<dependency>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap-convert-spi</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>

View File

@ -23,6 +23,10 @@ public class PluginConfigure
// Auto cleanup, only effective when unloading
public boolean autoCleanup;
// 同一目录下多个插件是否共享类加载器
// Whether multiple plugins in the same directory share the class loader
public boolean shareClassLoaderWhenSameDir;
public static PluginConfigure defaultConfig()
{
return PluginConfigure.builder()

View File

@ -437,7 +437,7 @@ public class PluginManager
else {
// 如果是目录则遍历加载
// Load plugins from directory
try (Stream<Path> paths = Files.walk(pluginsPath, config.getScanDepth())) {
try (Stream<Path> paths = Files.walk(pluginsPath, config.getScanDepth() == 0 ? 1 : config.getScanDepth())) {
paths.filter(Files::isDirectory)
.peek(path -> log.debug("Scanning plugin directory: {}", path))
.filter(path -> !path.equals(pluginsPath))
@ -466,18 +466,47 @@ public class PluginManager
String pluginVersion = VersionUtils.determinePluginVersion(pluginDir);
log.debug("Found plugin version: {}", pluginVersion);
// 创建插件专用类加载器
// Create plugin-specific class loader
PluginClassLoader loader = PluginClassLoaderUtils.createClassLoader(
pluginDir,
pluginBaseName,
pluginVersion
);
PluginClassLoader loader;
if (config.shareClassLoaderWhenSameDir) {
log.info("Use shared ClassLoader for plugin: {} at {}", pluginBaseName, pluginDir);
// 多个插件在同一目录下使用同一个类加载器
// Multiple plugins in the same directory, use the same class loader
loader = pluginClassLoaders.computeIfAbsent(
pluginDir.toString(),
k -> {
try {
return PluginClassLoaderUtils.createClassLoader(pluginDir, pluginBaseName, pluginVersion);
}
catch (Exception e) {
log.error("Failed to create ClassLoader for plugin: {} at {}", pluginBaseName, pluginDir, e);
return null;
}
}
);
}
else {
log.info("Use independent ClassLoader for plugin: {} at {}", pluginBaseName, pluginDir);
// 创建插件专用类加载器
// Create plugin-specific class loader
loader = PluginClassLoaderUtils.createClassLoader(
pluginDir,
pluginBaseName,
pluginVersion
);
}
if (loader == null) {
log.error("Failed to create ClassLoader for plugin: {} at {} skipped", pluginBaseName, pluginDir);
return;
}
List<Plugin> modules = PluginContextManager.runWithClassLoader(loader, () -> PluginLoaderFactory.loadPlugins(pluginDir));
for (Plugin module : modules) {
PluginContextManager.runWithClassLoader(loader, () -> {
log.debug("Loader version: {}", loader.getPluginVersion());
log.debug("Module loader version: {}", module.getPluginClassLoader().getPluginVersion());
// 为每个插件模块创建独立的注入器
// Create separate injector for each plugin module
Injector pluginInjector = Guice.createInjector(module);
@ -486,7 +515,12 @@ public class PluginManager
String pluginName = module.getName();
// 保存类加载器信息
// Save class loader information
pluginClassLoaders.put(pluginName, loader);
if (config.shareClassLoaderWhenSameDir) {
pluginClassLoaders.putIfAbsent(pluginName, loader);
}
else {
pluginClassLoaders.put(pluginName, loader);
}
PluginMetadata pluginMetadata = PluginMetadata.builder()
.name(pluginName)
@ -510,8 +544,8 @@ public class PluginManager
plugins.put(pluginName, pluginMetadata);
log.info("Install plugin: [ {} ] type [ {} ] version [ {} ] loader [ {} ] from source [ {} ]",
pluginName, module.getType().getName(), module.getVersion(), pluginMetadata.getLoaderName(), pluginDir);
log.info("Install plugin: [ {} ] type [ {} ] version [ {} ] loader [ {} ] from source [ {} ] loader name [ {} ]",
pluginName, module.getType().getName(), module.getVersion(), pluginMetadata.getLoaderName(), pluginDir, loader.getName());
return null;
});

View File

@ -14,6 +14,8 @@ import java.net.URLClassLoader;
public class PluginClassLoader
extends URLClassLoader
{
@Getter
private final String name;
@Getter
private final String pluginName;
@ -26,6 +28,7 @@ public class PluginClassLoader
super(urls, parent);
this.pluginName = pluginName;
this.pluginVersion = pluginVersion;
this.name = String.join("-", "loader", pluginName.toLowerCase(), pluginVersion.toLowerCase());
}
@Override

View File

@ -1,9 +1,14 @@
package io.edurt.datacap.plugin.utils;
import io.edurt.datacap.plugin.Plugin;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
@ -176,14 +181,14 @@ public class VersionUtils
.collect(Collectors.toList());
for (Path jarPath : jarFiles) {
String version = readVersionFromJar(jarPath);
String version = readVersionFromPluginJar(jarPath);
if (version != null) {
return version;
}
}
}
else if (pluginPath.toString().endsWith(".jar")) {
return readVersionFromJar(pluginPath);
return readVersionFromPluginJar(pluginPath);
}
}
catch (IOException e) {
@ -192,6 +197,77 @@ public class VersionUtils
return null;
}
/**
* Read version from a JAR file, but only if it contains a Plugin class
*/
private static String readVersionFromPluginJar(Path jarPath)
{
try (JarFile jarFile = new JarFile(jarPath.toFile())) {
// 首先检查是否包含 Plugin 类的实现
// Check if the JAR contains a Plugin class
if (!containsPluginClass(jarFile)) {
return null;
}
// TODO: 如果是插件JAR则从文件名中提取版本
// TODO: If the JAR is a plugin JAR, extract the version from the file name
String fileName = jarPath.getFileName().toString();
// 如果文件名中没有版本尝试从 MANIFEST.MF 读取
// If the version is not in the file name, try to read it from the MANIFEST.MF
Manifest manifest = jarFile.getManifest();
if (manifest != null) {
String version = getVersionFromManifest(manifest);
if (version != null) {
log.debug("Found version {} from plugin JAR manifest: {}", version, fileName);
return version;
}
}
}
catch (IOException e) {
log.debug("Failed to read from JAR: {}", jarPath, e);
}
return null;
}
/**
* Check if JAR contains a Plugin class implementation
*/
private static boolean containsPluginClass(JarFile jarFile)
{
try {
// 使用临时类加载器来加载和检查类
// Use a temporary class loader to load and check the class
try (URLClassLoader classLoader = new URLClassLoader(
new URL[] {new File(jarFile.getName()).toURI().toURL()}, Plugin.class.getClassLoader())) {
return jarFile.stream()
.filter(entry -> entry.getName().endsWith(".class"))
.anyMatch(entry -> {
String className = entry.getName()
.replace('/', '.')
.replace('\\', '.')
.replace(".class", "");
try {
Class<?> clazz = classLoader.loadClass(className);
return Plugin.class.isAssignableFrom(clazz) &&
!Modifier.isAbstract(clazz.getModifiers()) &&
!clazz.equals(Plugin.class);
}
catch (ClassNotFoundException | NoClassDefFoundError e) {
// 忽略加载失败的类
// Ignore classes that fail to load
return false;
}
});
}
}
catch (IOException e) {
log.debug("Failed to check for Plugin class in JAR: {}", jarFile.getName(), e);
return false;
}
}
/**
* Read version from a JAR file
*/

View File

@ -116,6 +116,10 @@
<artifactId>datacap-plugin</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap-convert-spi</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>io.edurt.datacap</groupId>-->
<!-- <artifactId>datacap-jdbc-clickhouse</artifactId>-->

View File

@ -33,7 +33,6 @@ public class PluginConfiguration
Path projectRoot = PluginPathUtils.findProjectRoot();
io.edurt.datacap.plugin.PluginConfigure config = io.edurt.datacap.plugin.PluginConfigure.builder()
.pluginsDir(PluginPathUtils.appendPath("plugins"))
.scanDepth(2)
.build();
// 开发模式下生效

View File

@ -82,34 +82,9 @@
<version>${datacap.influxdb.version}</version>
<scope>provided</scope>
</dependency>
<!-- Support convert -->
<dependency>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap-convert-txt</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap-convert-json</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap-convert-none</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap-convert-csv</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap-convert-xml</artifactId>
<artifactId>datacap-convert-spi</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>

View File

@ -15,6 +15,8 @@
<properties>
<clickhouse-jdbc.version>0.6.5</clickhouse-jdbc.version>
<httpclient5.version>5.3.1</httpclient5.version>
<lz4.version>1.8.0</lz4.version>
</properties>
<dependencies>
@ -37,13 +39,13 @@
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3.1</version>
<version>${httpclient5.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.lz4</groupId>
<artifactId>lz4-java</artifactId>
<version>1.8.0</version>
<version>${lz4.version}</version>
</dependency>
</dependencies>