All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.ideaaedi.component.dump.NonExitDumpClassExecutor Maven / Gradle / Ivy
package com.ideaaedi.component.dump;
import com.ideaaedi.commonds.bash.BashUtil;
import com.ideaaedi.commonds.io.IOUtil;
import com.ideaaedi.commonds.jar.JarUtil;
import com.ideaaedi.commonds.path.PathUtil;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* 与{@link ExitDumpClassExecutor}相比,此工具类dump结束后不会退出程序,其余注意事项见{@link ExitDumpClassExecutor}
*
* @author JustryDeng
* @since 2021/9/25 19:40:06
*/
@Slf4j
public class NonExitDumpClassExecutor {
/** 与pom中的2.3.0 同 */
public static final String VERSION = "2.3.0";
public static final String EXEC_DUMP_JAR = String.format("component-dump-class-%s.jar", VERSION);
/**
* @see NonExitDumpClassExecutor#exec(String, String)
*/
public static Map exec(String includePrefixes) {
return exec(BashUtil.currPid(), includePrefixes);
}
/**
* @see NonExitDumpClassExecutor#exec(String, String, String)
*/
public static Map exec(String pid, String includePrefixes) {
return exec(pid, includePrefixes, null);
}
/**
* dump 指定JVM中的class
*
* @param pid
* 要被进行dump操作的JVM进程id
* @param includePrefixes
* 要dump的class的全类名前缀,多个使用逗号分割
* @param excludePrefixes
* 明确排除dump的class的全类名前缀,多个使用逗号分割
*
* @return key - 全类名, value - class字节码
*/
public static Map exec(String pid, String includePrefixes, String excludePrefixes) {
// 获取当前类所在的jar包的路径作为agentJarPath
String execDumpJarPath = PathUtil.getProjectRootDir(NonExitDumpClassExecutor.class);
if (!execDumpJarPath.endsWith(EXEC_DUMP_JAR)) {
// 那么有可能component-dump-class作为lib包存在
if (!execDumpJarPath.endsWith(".jar")) {
// 找不到component-dump-class jar包
throw new IllegalStateException(String.format("So, where is %s ?", EXEC_DUMP_JAR));
}
String tmpDir = execDumpJarPath.substring(0, execDumpJarPath.lastIndexOf("/") + 1) + "_temp_/component"
+ "-dump-class/";
List list = new ArrayList<>();
list.add("/lib/" + EXEC_DUMP_JAR);
list.add("/BOOT-INF/lib/" + EXEC_DUMP_JAR);
List execJarPathList = JarUtil.unJarWar(execDumpJarPath, tmpDir, true, list);
if (execJarPathList == null || execJarPathList.size() == 0) {
// 找不到component-dump-class jar包
throw new IllegalStateException(String.format("So, where is %s ?", EXEC_DUMP_JAR));
}
execDumpJarPath = execJarPathList.get(0);
}
String outputDir =
execDumpJarPath.substring(0, execDumpJarPath.lastIndexOf("/") + 1) + "dump_" + System.currentTimeMillis() + "/";
String consoleInfoFormat = "\n[INFO] dump-class-process consoleInfo start ------------------------------------------------------------\n"
+ "%s"
+ "[INFO] dump-class-process consoleInfo end ------------------------------------------------------------\n";
// 单独起一个java进程,来执行dump, 该进程执行完dump后,会自己结束程序
final String finalExecDumpJarPath = execDumpJarPath;
try {
String consoleInfo = CompletableFuture.supplyAsync(() -> BashUtil.runBash(String.format("java -jar %s "
+ "pid=%s includePrefixes=%s excludePrefixes=%s outputDir=%s keepLongName=%s",
finalExecDumpJarPath, pid == null ? "" : pid, includePrefixes == null ? "" : includePrefixes,
excludePrefixes == null ? "" : excludePrefixes, outputDir, true))).get(30, TimeUnit.SECONDS);
log.info(String.format(consoleInfoFormat, consoleInfo));
} catch (Exception e) {
log.info(String.format(consoleInfoFormat, e.getMessage()));
return Collections.emptyMap();
}
File dir = new File(outputDir);
if (!dir.exists()) {
return Collections.emptyMap();
}
TreeMap classBytes = IOUtil.listFileOnly(dir, ".class").stream()
.collect(
Collectors.toMap(
// ".class".length() == 6
file -> file.getName().substring(0, file.getName().length() - 6),
IOUtil::toBytes,
(pre, next) -> next,
TreeMap::new
)
);
try {
IOUtil.delete(dir);
} catch (Exception e) {
// ignore
}
return classBytes;
}
}