mirror of
https://gitee.com/arthas/arthas.git
synced 2024-12-04 21:28:10 +08:00
Classloader support matching classloader by class name. (#1428)
This commit is contained in:
parent
92dd9a2fb0
commit
3dc3f36b9d
@ -13,6 +13,7 @@ import com.taobao.arthas.core.shell.command.AnnotatedCommand;
|
|||||||
import com.taobao.arthas.core.shell.command.CommandProcess;
|
import com.taobao.arthas.core.shell.command.CommandProcess;
|
||||||
import com.taobao.arthas.core.shell.handlers.Handler;
|
import com.taobao.arthas.core.shell.handlers.Handler;
|
||||||
import com.taobao.arthas.core.util.ClassUtils;
|
import com.taobao.arthas.core.util.ClassUtils;
|
||||||
|
import com.taobao.arthas.core.util.ClassLoaderUtils;
|
||||||
import com.taobao.arthas.core.util.ResultUtils;
|
import com.taobao.arthas.core.util.ResultUtils;
|
||||||
import com.taobao.arthas.core.util.affect.RowAffect;
|
import com.taobao.arthas.core.util.affect.RowAffect;
|
||||||
import com.taobao.middleware.cli.annotations.Description;
|
import com.taobao.middleware.cli.annotations.Description;
|
||||||
@ -56,6 +57,7 @@ public class ClassLoaderCommand extends AnnotatedCommand {
|
|||||||
private Logger logger = LoggerFactory.getLogger(ClassLoaderCommand.class);
|
private Logger logger = LoggerFactory.getLogger(ClassLoaderCommand.class);
|
||||||
private boolean isTree = false;
|
private boolean isTree = false;
|
||||||
private String hashCode;
|
private String hashCode;
|
||||||
|
private String classLoaderClass;
|
||||||
private boolean all = false;
|
private boolean all = false;
|
||||||
private String resource;
|
private String resource;
|
||||||
private boolean includeReflectionClassLoader = true;
|
private boolean includeReflectionClassLoader = true;
|
||||||
@ -71,6 +73,12 @@ public class ClassLoaderCommand extends AnnotatedCommand {
|
|||||||
isTree = tree;
|
isTree = tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Option(longName = "classLoaderClass")
|
||||||
|
@Description("The class name of the special class's classLoader.")
|
||||||
|
public void setClassLoaderClass(String classLoaderClass) {
|
||||||
|
this.classLoaderClass = classLoaderClass;
|
||||||
|
}
|
||||||
|
|
||||||
@Option(shortName = "c", longName = "classloader")
|
@Option(shortName = "c", longName = "classloader")
|
||||||
@Description("The hash code of the special ClassLoader")
|
@Description("The hash code of the special ClassLoader")
|
||||||
public void setHashCode(String hashCode) {
|
public void setHashCode(String hashCode) {
|
||||||
@ -113,6 +121,25 @@ public class ClassLoaderCommand extends AnnotatedCommand {
|
|||||||
process.interruptHandler(new ClassLoaderInterruptHandler(this));
|
process.interruptHandler(new ClassLoaderInterruptHandler(this));
|
||||||
|
|
||||||
Instrumentation inst = process.session().getInstrumentation();
|
Instrumentation inst = process.session().getInstrumentation();
|
||||||
|
|
||||||
|
if (!all && hashCode == null && classLoaderClass != null) {
|
||||||
|
List<ClassLoader> matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst, classLoaderClass);
|
||||||
|
if (matchedClassLoaders.size() == 1) {
|
||||||
|
hashCode = "" + Integer.toHexString(matchedClassLoaders.get(0).hashCode());
|
||||||
|
} else if (matchedClassLoaders.size() > 1) {
|
||||||
|
Collection<ClassLoaderVO> classLoaderVOList = ClassUtils.createClassLoaderVOList(matchedClassLoaders);
|
||||||
|
ClassLoaderModel classloaderModel = new ClassLoaderModel()
|
||||||
|
.setClassLoaderClass(classLoaderClass)
|
||||||
|
.setMatchedClassLoaders(classLoaderVOList);
|
||||||
|
process.appendResult(classloaderModel);
|
||||||
|
process.end(-1, "Found more than one classloader by class name, please specify classloader with '-c <classloader hash>'");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
process.end(-1, "Can not find classloader by class name: " + classLoaderClass + ".");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (all) {
|
if (all) {
|
||||||
processAllClasses(process, inst);
|
processAllClasses(process, inst);
|
||||||
} else if (hashCode != null && resource != null) {
|
} else if (hashCode != null && resource != null) {
|
||||||
|
@ -4,6 +4,7 @@ import com.taobao.arthas.core.command.klass100.ClassLoaderCommand.ClassLoaderSta
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author gongdewei 2020/4/21
|
* @author gongdewei 2020/4/21
|
||||||
@ -20,6 +21,9 @@ public class ClassLoaderModel extends ResultModel {
|
|||||||
|
|
||||||
private Map<String, ClassLoaderStat> classLoaderStats;
|
private Map<String, ClassLoaderStat> classLoaderStats;
|
||||||
|
|
||||||
|
private Collection<ClassLoaderVO> matchedClassLoaders;
|
||||||
|
private String classLoaderClass;
|
||||||
|
|
||||||
public ClassLoaderModel() {
|
public ClassLoaderModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,4 +94,22 @@ public class ClassLoaderModel extends ResultModel {
|
|||||||
this.classLoaderStats = classLoaderStats;
|
this.classLoaderStats = classLoaderStats;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getClassLoaderClass() {
|
||||||
|
return classLoaderClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassLoaderModel setClassLoaderClass(String classLoaderClass) {
|
||||||
|
this.classLoaderClass = classLoaderClass;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<ClassLoaderVO> getMatchedClassLoaders() {
|
||||||
|
return matchedClassLoaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassLoaderModel setMatchedClassLoaders(Collection<ClassLoaderVO> matchedClassLoaders) {
|
||||||
|
this.matchedClassLoaders = matchedClassLoaders;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,12 @@ public class ClassLoaderView extends ResultView<ClassLoaderModel> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(CommandProcess process, ClassLoaderModel result) {
|
public void draw(CommandProcess process, ClassLoaderModel result) {
|
||||||
|
if (result.getMatchedClassLoaders() != null) {
|
||||||
|
process.write("Matched classloaders: \n");
|
||||||
|
drawClassLoaders(process, result.getMatchedClassLoaders(), false);
|
||||||
|
process.write("\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (result.getClassSet() != null) {
|
if (result.getClassSet() != null) {
|
||||||
drawAllClasses(process, result.getClassSet());
|
drawAllClasses(process, result.getClassSet());
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ classloader
|
|||||||
|[t]|打印所有ClassLoader的继承树|
|
|[t]|打印所有ClassLoader的继承树|
|
||||||
|[a]|列出所有ClassLoader加载的类,请谨慎使用|
|
|[a]|列出所有ClassLoader加载的类,请谨慎使用|
|
||||||
|`[c:]`|ClassLoader的hashcode|
|
|`[c:]`|ClassLoader的hashcode|
|
||||||
|
|`[classLoaderClass:]`|指定执行表达式的 ClassLoader 的 class name|
|
||||||
|`[c: r:]`|用ClassLoader去查找resource|
|
|`[c: r:]`|用ClassLoader去查找resource|
|
||||||
|`[c: load:]`|用ClassLoader去加载指定的类|
|
|`[c: load:]`|用ClassLoader去加载指定的类|
|
||||||
|
|
||||||
@ -67,6 +68,18 @@ file:/Users/hengyunabc/.arthas/lib/3.0.5/arthas/arthas-agent.jar
|
|||||||
Affect(row-cnt:9) cost in 3 ms.
|
Affect(row-cnt:9) cost in 3 ms.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
*注意* hashcode是变化的,需要先查看当前的ClassLoader信息,提取对应ClassLoader的hashcode。
|
||||||
|
|
||||||
|
对于只有唯一实例的ClassLoader可以通过class name指定,使用起来更加方便:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ classloader --classLoaderClass sun.misc.Launcher$AppClassLoader
|
||||||
|
file:/private/tmp/arthas-demo.jar
|
||||||
|
file:/Users/hengyunabc/.arthas/lib/3.0.5/arthas/arthas-agent.jar
|
||||||
|
|
||||||
|
Affect(row-cnt:9) cost in 3 ms.
|
||||||
|
```
|
||||||
|
|
||||||
#### 使用ClassLoader去查找resource
|
#### 使用ClassLoader去查找resource
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
@ -13,6 +13,7 @@ View hierarchy, urls and classes-loading info for the class-loaders.
|
|||||||
|[t]|print classloader's hierarchy|
|
|[t]|print classloader's hierarchy|
|
||||||
|[a]|list all the classes loaded by all the classloaders (use it with great caution since the output can be huge)|
|
|[a]|list all the classes loaded by all the classloaders (use it with great caution since the output can be huge)|
|
||||||
|[c:]|print classloader's hashcode|
|
|[c:]|print classloader's hashcode|
|
||||||
|
|`[classLoaderClass:]`| The class name of the ClassLoader that executes the expression. |
|
||||||
|`[c: r:]`|using ClassLoader to search resource|
|
|`[c: r:]`|using ClassLoader to search resource|
|
||||||
|`[c: load:]`|using ClassLoader to load class|
|
|`[c: load:]`|using ClassLoader to load class|
|
||||||
|
|
||||||
@ -64,6 +65,18 @@ file:/Users/hengyunabc/.arthas/lib/3.0.5/arthas/arthas-agent.jar
|
|||||||
Affect(row-cnt:9) cost in 3 ms.
|
Affect(row-cnt:9) cost in 3 ms.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note that the hashcode changes, you need to check the current ClassLoader information first, and extract the hashcode corresponding to the ClassLoader.
|
||||||
|
|
||||||
|
For ClassLoader with only unique instance, it can be specified by class name, which is more convenient to use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ classloader --classLoaderClass sun.misc.Launcher$AppClassLoader
|
||||||
|
file:/private/tmp/arthas-demo.jar
|
||||||
|
file:/Users/hengyunabc/.arthas/lib/3.0.5/arthas/arthas-agent.jar
|
||||||
|
|
||||||
|
Affect(row-cnt:9) cost in 3 ms.
|
||||||
|
```
|
||||||
|
|
||||||
#### Use the classloader to load resource
|
#### Use the classloader to load resource
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
Loading…
Reference in New Issue
Block a user