You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java Agent的premain中获取目标Jar的Manifest属性?

如何在Java Agent的premain方法中获取目标Jar的Main-Class属性

你可以通过两种可靠的方式在premain阶段直接读取目标Jar的Manifest,无需手动传入主类参数:

方案一:解析启动命令行获取目标Jar路径

通过系统属性sun.java.command可以拿到完整的Java启动命令,从中提取-jar参数后的目标Jar路径,直接读取其Manifest。这个方法能精准定位你启动的目标Jar,避免遍历类加载器时的误判。

代码示例:

import java.io.File;
import java.io.IOException;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

public class MyAgent {
    public static void premain(String agentArgs, java.lang.instrument.Instrumentation inst) {
        // 获取完整启动命令
        String launchCommand = System.getProperty("sun.java.command");
        if (launchCommand == null) {
            return;
        }

        // 拆分命令参数,定位-jar后的Jar路径
        String[] cmdParts = launchCommand.split("\\s+");
        for (int i = 0; i < cmdParts.length; i++) {
            if ("-jar".equals(cmdParts[i]) && i + 1 < cmdParts.length) {
                String targetJarPath = cmdParts[i + 1];
                File targetJar = new File(targetJarPath);
                
                if (!targetJar.exists()) {
                    // 处理Jar路径含空格的情况(split会拆分,需要拼接)
                    StringBuilder jarPathBuilder = new StringBuilder(targetJarPath);
                    for (int j = i + 2; j < cmdParts.length; j++) {
                        jarPathBuilder.append(" ").append(cmdParts[j]);
                        if (new File(jarPathBuilder.toString()).exists()) {
                            targetJarPath = jarPathBuilder.toString();
                            targetJar = new File(targetJarPath);
                            break;
                        }
                    }
                }

                try (JarFile jarFile = new JarFile(targetJar)) {
                    Manifest manifest = jarFile.getManifest();
                    if (manifest != null) {
                        String mainClass = manifest.getMainAttributes().getValue("Main-Class");
                        // 拿到主类后执行你的逻辑
                        System.out.println("目标Jar的Main-Class: " + mainClass);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }
}

注意:sun.java.command是OpenJDK/Oracle JDK的私有属性,多数主流JDK实现都支持,但小众JDK可能不兼容。另外代码中处理了Jar路径含空格的情况,避免split拆分后路径不完整。

方案二:遍历系统类加载器的URL读取Manifest

目标Jar会被系统类加载器加载,你可以遍历系统类加载器的URL集合,找到对应Jar文件后读取其Manifest。

代码示例:

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

public class MyAgent {
    public static void premain(String agentArgs, java.lang.instrument.Instrumentation inst) {
        ClassLoader systemCL = ClassLoader.getSystemClassLoader();
        if (!(systemCL instanceof URLClassLoader)) {
            // 非URLClassLoader场景(如模块化环境),此方法不适用
            return;
        }

        URLClassLoader urlCL = (URLClassLoader) systemCL;
        for (URL url : urlCL.getURLs()) {
            try {
                String urlStr = url.toString();
                // 筛选Jar类型的URL
                if (!urlStr.startsWith("jar:file:")) {
                    continue;
                }

                // 转换为本地文件路径,处理URL编码(如空格转%20)
                String filePath = urlStr.substring("jar:file:".length());
                if (filePath.endsWith("!/")) {
                    filePath = filePath.substring(0, filePath.length() - 2);
                }
                filePath = URLDecoder.decode(filePath, StandardCharsets.UTF_8.name());
                File jarFile = new File(filePath);

                // 根据文件名判断是否是目标Jar(替换成你的Jar文件名)
                if (!jarFile.getName().equals("sample-code.jar")) {
                    continue;
                }

                try (JarFile jar = new JarFile(jarFile)) {
                    Manifest manifest = jar.getManifest();
                    if (manifest != null) {
                        String mainClass = manifest.getMainAttributes().getValue("Main-Class");
                        System.out.println("目标Jar的Main-Class: " + mainClass);
                    }
                }
                break;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

注意:如果系统类加载器不是URLClassLoader(比如Java 9+的模块化应用),此方法失效,此时建议优先用方案一。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 05:45:40