如何获取java运行时动态生成的字节码文件?

  查看运行时生成的文件,以更清楚运行情况。

  查看动态生成的类,一般有两个方法:

1. 使用sd-jdi.jar里的工具。

其中,不想自己搞,当然就利用下,sd-jdi.jar 里自带的的sun.jvm.hotspot.tools.jcore.ClassDump就可以把类的class内容dump到文件里。

ClassDump里可以设置两个System properties:

  sun.jvm.hotspot.tools.jcore.filter Filter的类名
  sun.jvm.hotspot.tools.jcore.outputDir 输出的目录

sd-jdi.jar 里有一个sun.jvm.hotspot.tools.jcore.PackageNameFilter,可以指定Dump哪些包里的类。PackageNameFilter里有一个System property可以指定过滤哪些包:sun.jvm.hotspot.tools.jcore.PackageNameFilter.pkgList。

所以可以通过这样子的命令来使用:

sudo java -classpath "$JAVA_HOME/lib/sa-jdi.jar" -Dsun.jvm.hotspot.tools.jcore.filter=sun.jvm.hotspot.tools.jcore.PackageNameFilter -Dsun.jvm.hotspot.tools.jcore.PackageNameFilter.pkgList=com.test sun.jvm.hotspot.tools.jcore.ClassDump <pid>

不过,我在windows下并没有成功过,原因是还要要求我 start SwDbgSrv.exe,搞不了。

其中sa-jdi.jar文件也不那么好找呢,不过也能找到!

所以,还不如自己动手,丰衣足食!


2. 自己重写一个记录工具,用agent attatch 到进程,然后利用Instrumentation和ClassFileTransformer就可以获取 到类的字节码了。

工具类如下:

package com.xxx.test; import java.io.File; import java.io.FileOutputStream; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.lang.instrument.Instrumentation; import java.security.ProtectionDomain; /** * 动态生成类拦截查看工具 * * @date 2018/9/15 */ public class ClazzDumpCustomAgent implements ClassFileTransformer { /** * 导出过滤表达式,此处为类名前缀,使用 -f 进行输入 */ private String filterStr; /** * 导出文件目录根目录, 使用 -d 进行输入 */ private String exportBaseDir = "/tmp/"; public ClazzDumpCustomAgent(String exportBaseDir, String filterStr) { if(exportBaseDir != null) { this.exportBaseDir = exportBaseDir; } this.filterStr = filterStr; } /** * 入口地址 * * @param agentArgs agent参数 * @param inst */ public static void premain(String agentArgs, Instrumentation inst) { System.out.println("agentArgs: " + agentArgs); String exportDir = null; String filterStr = null; if(agentArgs != null) { if(agentArgs.contains(";")) { String[] args = agentArgs.split(";"); for (String param1 : args) { String[] kv = param1.split("="); if("-d".equalsIgnoreCase(kv[0])) { exportDir = kv[1]; } else if("-f".equalsIgnoreCase(kv[0])) { filterStr = kv[1]; } } } else { filterStr = agentArgs; } } inst.addTransformer(new ClazzDumpCustomAgent(exportDir, filterStr)); } @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if (needExportClass(className)) { int lastSeperatorIndex = className.lastIndexOf("http://www.likecs.com/") + 1; String fileName = className.substring(lastSeperatorIndex) + ".class"; exportClazzToFile(exportBaseDir, fileName, classfileBuffer); //"D:/server-tool/tmp/bytecode/exported/" System.out.println(className + " --> EXPORTED"); } return classfileBuffer; } /** * 检测是否需要进行文件导出 * * @param className class名,如 com.xx.abc.AooMock * @return y/n */ private boolean needExportClass(String className) { if(filterStr != null) { if(className.startsWith(filterStr)) { return true; } else { return false; } } if (!className.startsWith("java") && !className.startsWith("sun")) { return true; } return false; } /** * 执行文件导出写入 * * @param dirPath 导出目录 * @param fileName 导出文件名 * @param data 字节流 */ private void exportClazzToFile(String dirPath, String fileName, byte[] data) { try { File dir = new File(dirPath); if(!dir.isDirectory()) { dir.mkdirs(); } File file = new File(dirPath + fileName); if (!file.exists()) { file.createNewFile(); } FileOutputStream fos = new FileOutputStream(file); fos.write(data); fos.close(); } catch (Exception e) { System.out.println("exception occured while doing some file operation"); e.printStackTrace(); } } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpdxjw.html