当前位置: 首页 > 知识库问答 >
问题:

使用NIO在外部JAR中加载所有类

长孙智刚
2023-03-14

我有一个插件文件夹,其中包含一些JAR,我想加载它们的所有*。班我看到很多关于JarFileZipEntry的答案。然而,我想用java来实现这一点。nio包而不是io。

我能做的是:

  1. 使用文件列出文件夹中的文件(例如列出我所有的JAR)。列表(路径)

我还不能做的事:

  1. 使用NIO在JAR/ZIP中列出文件

最终,我想要:

  1. 在几个JAR中遍历每个类,并加载它们以寻找一种插件系统的注释

我应该补充一点,我不需要一个使用像番石榴或阿帕奇这样的应用编程接口的工作解决方案,但我只想知道它是如何完成的。

我当前的代码:

import java.io.IOException;
import java.nio.file.*;
import java.security.SecureClassLoader;
import java.util.*;
public class PluginManager {

public final Path pluginFolder;

public PluginManager(Path pluginFolder) {
    this.pluginFolder = pluginFolder;
}


public void load() {
    final var pluginClassLoader = new SecureClassLoader(getClass().getClassLoader()){

        FileSystem jar;

        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            String pluginClassName = jar.getSeparator() + name.replaceAll("\\.", jar.getSeparator()) + ".class";
            try{
                byte[] bytes = Files.readAllBytes(jar.getPath(pluginClassName));
                return defineClass(name, bytes, 0, bytes.length);
            }catch(IOException e){
                e.printStackTrace();
            }
            throw new ClassNotFoundException("Failed to found "+name);
        }
    };

    try(Stream<Path> files = Files.list(pluginFolder)){
        files.filter((file) -> !Files.isDirectory(file) &&
                (file.toString().endsWith(".jar") || file.toString().endsWith(".zip")))
                .forEach(jar -> {

                    try(FileSystem fileSystem = FileSystems.newFileSystem(jar)){
                        pluginClassLoader.jar = fileSystem;
                        loadPlugin(fileSystem, pluginClassLoader);
                    }catch(IOException | ClassNotFoundException e){
                        e.printStackTrace();
                    }

                });
    }catch(IOException e){
        e.printStackTrace();
        throw new IllegalStateException("Failed to scan plugin folder. Cannot continue.");
    }

}

private void loadPlugin(FileSystem jar, SecureClassLoader classLoader) throws IOException, ClassNotFoundException{
    String className = ...  // here, we retrieve the plugin class name from a manifest file using FileSystem.getPath().
// what I want is to get rid of that manifest and to load and test every class.

    Class<?> clazz = classLoader.loadClass(className);
    // do stuff with loaded class
}

我想避免这样java.io代码:如何在运行时从文件夹或JAR加载类?

共有1个答案

景宏盛
2023-03-14

我无意中发现了zip文件夹及其子文件夹中的文件列表。我最初错过的这种方法不是用文件夹中的jar路径调用Files.walkFileTree(Path,FileVisitor),而是使用创建的FileSystem的根路径(使用FileSystem.getPath("/"))。这对我来说非常合适。

 类似资料:
  • 我将Jetty(8和9)与LZ4压缩一起使用,我想使用LZ4的本机实现,它是C库的本机绑定。为了实现这一点,LZ4类应该用系统类加载器加载。 所以我的问题是,如何用Jetty中的系统类加载器加载一个外部jar。 将lib放入$jetty。home/lib/ext没有帮助,因为它是用扩展类加载器而不是系统加载器加载的。

  • 我有一个带有spring boot的java项目,我需要加载应用程序。外部文件夹中的属性和依赖项jar。 我使用该应用程序进行了测试。类路径和加载程序中的属性。路径属性工作正常。 当我使用外部属性文件(我确信它们已被使用)时,加载程序。路径工作不正常,结果为ClassNotFound,因为JAR未加载。 此外,当我启动应用程序与**-Dloader.path=**xxx它的工作正常。 如何使用外部

  • 我尝试过在IntelliJ的project structure下通过库添加JAR,并只在根目录下的libs文件夹中添加JAR。首先,我提供了绝对路径,但后来我将其更改为${basedir},因为绝对路径没有映射为docker容器上的卷。有什么方法可以将外部jar与项目jar打包,以便在docker容器中使用它?

  • 现有一个springboot项目,通过扫描二维码查询信息,比如一棵树,扫描二维码后可以看到他相关的信息。但这个项目不止有树类型,还有道路,某个物品。所以将项目分模块开发,核心模块作为一个jar包,复制提供基础服务如数据导入导出。各类型构建成单独的jar。部署时需要那种类型就加载对应的jar。这样做是为了满足不同客户需求。 尝试: java -Xbootclasspath/a:file:./libs

  • 我尝试在pom中添加以下内容。xml 但没起作用。 我发现的更多信息: 它可能与SpringBootMaven插件有关。https://docs.spring.io/spring-boot/docs/current/maven-plugin/在构建jar时,它不包括作用域“系统”库。 裁判:https://github.com/spring-projects/spring-boot/blob/ma

  • 我正在开发一个Spring Boot应用程序。我想提供一个(相当初级的)插件系统。最初,我希望只将JAR添加到类路径中就足够了,如下所示: 此外,如果我尝试在插件控制器中一个JpaRepository,它会失败,因为它找不到存储库接口类(我猜这是因为我乱弄类加载器引起的问题)。 不过,在我的主应用程序中自动创建存储库就可以很好地工作,因此它的配置不应该是一个问题。 是不是我做错了什么?我是否可以配