如何在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
相关产品推荐
相关产品推荐

