You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Java程序运行时如何获取依赖列表?(无Maven环境)

在Java程序运行时获取依赖列表的几种方案

嘿,这个需求很常见,尤其是当你的程序要在没有Maven的环境运行时,总不能让用户手动去查依赖对吧?下面给你几个靠谱的实现方式:

1. 利用ClassLoader遍历已加载的Jar包

Java的类加载器可以获取到当前JVM中已加载的所有资源,其中就包含你的项目依赖的Jar文件。你可以写一段代码,遍历这些资源并提取Jar的名称和版本信息。

示例代码如下:

import java.net.URL;
import java.security.CodeSource;
import java.util.HashSet;
import java.util.Set;

public class DependencyLogger {
    public static void logDependencies() {
        Set<String> dependencies = new HashSet<>();
        // 获取当前类的类加载器
        ClassLoader classLoader = DependencyLogger.class.getClassLoader();
        
        if (classLoader instanceof java.net.URLClassLoader) {
            URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
            for (URL url : urlClassLoader.getURLs()) {
                String urlStr = url.getFile();
                // 过滤出Jar文件,提取名称
                if (urlStr.endsWith(".jar")) {
                    String jarName = urlStr.substring(urlStr.lastIndexOf('/') + 1);
                    dependencies.add(jarName);
                }
            }
        }
        
        // 打印依赖列表
        System.out.println("当前程序依赖的Jar包:");
        for (String dep : dependencies) {
            System.out.println("- " + dep);
        }
    }

    public static void main(String[] args) {
        logDependencies();
        // 你的程序逻辑...
    }
}

注意:这种方式只能获取到已经被类加载器加载的Jar包,如果有些依赖是动态加载的,可能不会被列出来。

2. 打包时嵌入依赖清单(推荐)

如果你用Maven打包,可以借助maven-shade-plugin或者maven-resources-plugin,在打包阶段把dependency:tree的结果写入到Jar包内部的一个文件中,然后程序启动时直接读取这个文件即可。

步骤1:配置Maven插件,嵌入依赖信息

pom.xml中添加以下配置,让Maven在打包时生成依赖列表文件:

<build>
    <plugins>
        <!-- 生成依赖树并写入文件 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>3.6.0</version>
            <executions>
                <execution>
                    <id>generate-dependency-tree</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>tree</goal>
                    </goals>
                    <configuration>
                        <outputFile>${project.build.outputDirectory}/dependencies.txt</outputFile>
                        <outputType>text</outputType>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <!-- 打包时包含生成的依赖文件 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.3.0</version>
            <configuration>
                <includes>
                    <include>**/dependencies.txt</include>
                </includes>
            </configuration>
        </plugin>
    </plugins>
</build>

步骤2:程序启动时读取依赖文件

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

public class DependencyLogger {
    public static void logDependencies() {
        try (InputStream is = DependencyLogger.class.getResourceAsStream("/dependencies.txt");
             BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
            
            String line;
            System.out.println("程序依赖列表:");
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (Exception e) {
            System.err.println("读取依赖列表失败:" + e.getMessage());
        }
    }

    public static void main(String[] args) {
        logDependencies();
        // 你的程序逻辑...
    }
}

这种方式的优点是能获取到完整的依赖树(包括传递依赖),而且不需要在运行时依赖任何工具,完全依赖打包阶段生成的静态文件。

3. Java 9+模块化项目:使用Module API

如果你的项目是基于Java 9及以上的模块化系统开发的,可以直接使用Module API来获取模块的依赖信息:

import java.lang.module.ModuleDescriptor;
import java.util.Set;

public class DependencyLogger {
    public static void logDependencies() {
        // 获取当前模块的描述符
        Module currentModule = DependencyLogger.class.getModule();
        ModuleDescriptor descriptor = currentModule.getDescriptor();
        
        // 获取依赖的模块
        Set<ModuleDescriptor.Requires> requires = descriptor.requires();
        
        System.out.println("当前模块依赖的模块:");
        for (ModuleDescriptor.Requires req : requires) {
            System.out.println("- " + req.name() + (req.version().isPresent() ? " (版本:" + req.version().get() + ")" : ""));
        }
    }

    public static void main(String[] args) {
        logDependencies();
        // 你的程序逻辑...
    }
}

注意:这种方式只适用于模块化项目,获取的是模块级别的依赖,而不是Jar包级别的。

内容的提问来源于stack exchange,提问作者Mattew Eon

火山引擎 最新活动