io.github.linyimin0812.profiler.extension.enhance.jar.JarCollector Maven / Gradle / Ivy
package io.github.linyimin0812.profiler.extension.enhance.jar;
import io.github.linyimin0812.profiler.api.Lifecycle;
import io.github.linyimin0812.profiler.common.logger.LogFactory;
import io.github.linyimin0812.profiler.common.instruction.InstrumentationHolder;
import io.github.linyimin0812.profiler.common.ui.StartupVO;
import io.github.linyimin0812.profiler.common.ui.Statistics;
import org.kohsuke.MetaInfServices;
import org.slf4j.Logger;
import java.lang.instrument.Instrumentation;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.*;
/**
* @author linyimin
**/
@MetaInfServices(Lifecycle.class)
public class JarCollector implements Lifecycle {
private static final Logger logger = LogFactory.getStartupLogger();
private Map> usedJarMap;
private Map> unusedJarMap;
private void collect() {
usedJarMap = new HashMap<>();
unusedJarMap = new HashMap<>();
Instrumentation instrumentation = InstrumentationHolder.getInstrumentation();
for (Class> loadedClass : instrumentation.getAllLoadedClasses()) {
ClassLoader loader = loadedClass.getClassLoader();
if (loader == null
|| loader.toString().contains("ExtClassLoader")
|| loader.toString().contains("ProfilerAgentClassLoader")) {
continue;
}
ProtectionDomain protectionDomain = loadedClass.getProtectionDomain();
CodeSource codeSource = protectionDomain.getCodeSource();
if (codeSource == null) {
continue;
}
URL location = codeSource.getLocation();
if (location == null) {
continue;
}
Set urls = usedJarMap.computeIfAbsent(loader, k -> new HashSet<>());
urls.add(location.toString());
}
for (Map.Entry> entry : usedJarMap.entrySet()) {
ClassLoader loader = entry.getKey();
Set usedUrls = entry.getValue();
Set unusedUrls = new HashSet<>();
List allUrls = getClassLoaderUrls(loader);
for (String url : allUrls) {
if (usedUrls.contains(url)) {
continue;
}
unusedUrls.add(url);
}
if (!unusedUrls.isEmpty()) {
unusedJarMap.put(loader, unusedUrls);
}
}
}
private List getClassLoaderUrls(ClassLoader loader) {
List urls = new ArrayList<>();
if (loader instanceof URLClassLoader) {
URL[] loaderUrls = ((URLClassLoader) loader).getURLs();
if (loaderUrls == null) {
return urls;
}
for (URL url : loaderUrls) {
urls.add(url.toString());
}
}
return urls;
}
@Override
public void start() {
logger.info("=======================JarCollector start=======================");
}
@Override
public void stop() {
logger.info("=======================JarCollector stop=======================");
collect();
reportUnusedJarDetails();
}
private void reportUnusedJarDetails() {
long usedCount = usedJarMap.values().stream().mapToLong(Collection::size).sum();
long unusedCount = unusedJarMap.values().stream().mapToLong(Collection::size).sum();
StartupVO.addStatistics(new Statistics("Used/Total Jars", String.format("%s/%s", usedCount, usedCount + unusedCount)));
StartupVO.addStatistics(new Statistics("Unused/Total Jars", String.format("%s/%s", unusedCount, usedCount + unusedCount)));
StartupVO.addStatistics(new Statistics("ClassLoader Count", String.valueOf(usedJarMap.size())));
for (Map.Entry> entry : unusedJarMap.entrySet()) {
StartupVO.addUnusedJar(entry);
}
}
}