support arthas.enhanceLoaders config/add jboss ModuleClassLoader testcase. #1596

This commit is contained in:
hengyunabc
2020-12-02 00:55:00 +08:00
parent 9c847d2dd5
commit bc70853b0c
6 changed files with 127 additions and 7 deletions
+2
View File
@@ -6,6 +6,8 @@ arthas.ip=127.0.0.1
# seconds
arthas.sessionTimeout=1800
arthas.enhanceLoaders=java.lang.ClassLoader
#arthas.appName=demoapp
#arthas.tunnelServer=ws://127.0.0.1:7777/ws
#arthas.agentId=mmmmmmyiddddd
@@ -28,6 +28,11 @@ public class Configure {
private String tunnelServer;
private String agentId;
/**
* 需要被增强的ClassLoader的全类名,多个用英文 , 分隔
*/
private String enhanceLoaders;
/**
* <pre>
* 1. 如果显式传入 arthas.agentId ,则直接使用
@@ -135,6 +140,14 @@ public class Configure {
this.appName = appName;
}
public String getEnhanceLoaders() {
return enhanceLoaders;
}
public void setEnhanceLoaders(String enhanceLoaders) {
this.enhanceLoaders = enhanceLoaders;
}
/**
* 序列化成字符串
*
@@ -9,10 +9,12 @@ import java.lang.reflect.Method;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.Timer;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -25,9 +27,12 @@ import com.alibaba.arthas.deps.ch.qos.logback.classic.LoggerContext;
import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.alibaba.arthas.tunnel.client.TunnelClient;
import com.alibaba.bytekit.asm.instrument.InstrumentConfig;
import com.alibaba.bytekit.asm.instrument.InstrumentParseResult;
import com.alibaba.bytekit.asm.instrument.InstrumentTemplate;
import com.alibaba.bytekit.asm.instrument.InstrumentTransformer;
import com.alibaba.bytekit.asm.matcher.SimpleClassMatcher;
import com.alibaba.bytekit.utils.AsmUtils;
import com.alibaba.bytekit.utils.IOUtils;
import com.taobao.arthas.common.AnsiLog;
import com.taobao.arthas.common.ArthasConstants;
@@ -59,7 +64,9 @@ import com.taobao.arthas.core.shell.term.impl.http.api.HttpApiHandler;
import com.taobao.arthas.core.shell.term.impl.httptelnet.HttpTelnetTermServer;
import com.taobao.arthas.core.util.ArthasBanner;
import com.taobao.arthas.core.util.FileUtils;
import com.taobao.arthas.core.util.InstrumentationUtils;
import com.taobao.arthas.core.util.LogUtil;
import com.taobao.arthas.core.util.StringUtils;
import com.taobao.arthas.core.util.UserStatUtil;
import com.taobao.arthas.core.util.affect.EnhancerAffect;
import com.taobao.arthas.core.util.matcher.WildcardMatcher;
@@ -126,10 +133,12 @@ public class ArthasBootstrap {
// 3. init logger
loggerContext = LogUtil.initLooger(arthasEnvironment);
// 4. init beans
// 4. 增强ClassLoader
enhanceClassLoader();
// 5. init beans
initBeans();
// 5. start agent server
// 6. start agent server
bind(configure);
executorService = Executors.newScheduledThreadPool(1, new ThreadFactory() {
@@ -182,19 +191,38 @@ public class ArthasBootstrap {
throw new IllegalStateException("can not find " + ARTHAS_SPY_JAR);
}
}
}
void enhanceClassLoader() throws IOException, UnmodifiableClassException {
if (configure.getEnhanceLoaders() == null) {
return;
}
Set<String> loaders = new HashSet<String>();
for (String s : configure.getEnhanceLoaders().split(",")) {
loaders.add(s.trim());
}
// 增强 ClassLoader#loadClsss ,解决一些ClassLoader加载不到 SpyAPI的问题
// https://github.com/alibaba/arthas/issues/1596
InstrumentTemplate template = new InstrumentTemplate();
byte[] classBytes = IOUtils.getBytes(ArthasBootstrap.class.getClassLoader()
.getResourceAsStream(ClassLoader_Instrument.class.getName().replace('.', '/') + ".class"));
template.addInstrumentClass(classBytes);
InstrumentParseResult instrumentParseResult = template.build();
SimpleClassMatcher matcher = new SimpleClassMatcher(loaders);
InstrumentConfig instrumentConfig = new InstrumentConfig(AsmUtils.toClassNode(classBytes), matcher);
InstrumentParseResult instrumentParseResult = new InstrumentParseResult();
instrumentParseResult.addInstrumentConfig(instrumentConfig);
classLoaderInstrumentTransformer = new InstrumentTransformer(instrumentParseResult);
instrumentation.addTransformer(classLoaderInstrumentTransformer);
}
instrumentation.addTransformer(classLoaderInstrumentTransformer, true);
if (loaders.size() == 1 && loaders.contains(ClassLoader.class.getName())) {
// 如果只增强 java.lang.ClassLoader,可以减少查找过程
instrumentation.retransformClasses(ClassLoader.class);
} else {
InstrumentationUtils.trigerRetransformClasses(instrumentation, loaders);
}
}
private void initArthasEnvironment(Map<String, String> argsMap) throws IOException {
if (arthasEnvironment == null) {
arthasEnvironment = new ArthasEnvironment();
@@ -2,6 +2,7 @@ package com.taobao.arthas.core.util;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.util.Collection;
import java.util.Set;
import com.alibaba.arthas.deps.org.slf4j.Logger;
@@ -38,4 +39,17 @@ public class InstrumentationUtils {
inst.removeTransformer(transformer);
}
}
public static void trigerRetransformClasses(Instrumentation inst, Collection<String> classes) {
for (Class<?> clazz : inst.getAllLoadedClasses()) {
if (classes.contains(clazz.getName())) {
try {
inst.retransformClasses(clazz);
} catch (Throwable e) {
String errorMsg = "retransformClasses class error, name: " + clazz.getName();
logger.error(errorMsg, e);
}
}
}
}
}