Add --classLoaderClass for dump/getstatic/jad/mc/redifine (#1447)

This commit is contained in:
Hollow Man
2020-08-26 15:27:26 +08:00
committed by GitHub
parent ed70f644a3
commit e3283f0439
44 changed files with 589 additions and 42 deletions
@@ -4,6 +4,7 @@ import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.model.ClassVO;
import com.taobao.arthas.core.command.model.ClassLoaderVO;
import com.taobao.arthas.core.command.model.DumpClassModel;
import com.taobao.arthas.core.command.model.DumpClassVO;
import com.taobao.arthas.core.command.model.MessageModel;
@@ -14,6 +15,7 @@ import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.shell.command.ExitStatus;
import com.taobao.arthas.core.util.ClassUtils;
import com.taobao.arthas.core.util.ClassLoaderUtils;
import com.taobao.arthas.core.util.CommandUtils;
import com.taobao.arthas.core.util.InstrumentationUtils;
import com.taobao.arthas.core.util.SearchUtils;
@@ -32,6 +34,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Collection;
/**
@@ -51,6 +54,7 @@ public class DumpClassCommand extends AnnotatedCommand {
private String classPattern;
private String code = null;
private String classLoaderClass;
private boolean isRegEx = false;
private String directory;
@@ -69,6 +73,12 @@ public class DumpClassCommand extends AnnotatedCommand {
this.code = code;
}
@Option(longName = "classLoaderClass")
@Description("The class name of the special class's classLoader.")
public void setClassLoaderClass(String classLoaderClass) {
this.classLoaderClass = classLoaderClass;
}
@Option(shortName = "E", longName = "regex", flag = true)
@Description("Enable regular expression to match (wildcard matching by default)")
public void setRegEx(boolean regEx) {
@@ -101,7 +111,26 @@ public class DumpClassCommand extends AnnotatedCommand {
}
ExitStatus status = null;
Instrumentation inst = process.session().getInstrumentation();
if (code == null && classLoaderClass != null) {
List<ClassLoader> matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst, classLoaderClass);
if (matchedClassLoaders.size() == 1) {
code = Integer.toHexString(matchedClassLoaders.get(0).hashCode());
} else if (matchedClassLoaders.size() > 1) {
Collection<ClassLoaderVO> classLoaderVOList = ClassUtils.createClassLoaderVOList(matchedClassLoaders);
DumpClassModel dumpClassModel = new DumpClassModel()
.setClassLoaderClass(classLoaderClass)
.setMatchedClassLoaders(classLoaderVOList);
process.appendResult(dumpClassModel);
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;
}
}
Set<Class<?>> matchedClasses = SearchUtils.searchClass(inst, classPattern, isRegEx, code);
if (matchedClasses == null || matchedClasses.isEmpty()) {
status = processNoMatch(process);
@@ -6,6 +6,7 @@ import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.express.ExpressException;
import com.taobao.arthas.core.command.express.ExpressFactory;
import com.taobao.arthas.core.command.model.ClassVO;
import com.taobao.arthas.core.command.model.ClassLoaderVO;
import com.taobao.arthas.core.command.model.GetStaticModel;
import com.taobao.arthas.core.command.model.MessageModel;
import com.taobao.arthas.core.command.model.RowAffectModel;
@@ -13,6 +14,7 @@ import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.shell.command.ExitStatus;
import com.taobao.arthas.core.util.ClassUtils;
import com.taobao.arthas.core.util.ClassLoaderUtils;
import com.taobao.arthas.core.util.CommandUtils;
import com.taobao.arthas.core.util.SearchUtils;
import com.taobao.arthas.core.util.StringUtils;
@@ -31,6 +33,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Set;
import java.util.Collection;
/**
* @author diecui1202 on 2017/9/27.
@@ -50,6 +53,7 @@ public class GetStaticCommand extends AnnotatedCommand {
private String fieldPattern;
private String express;
private String hashCode = null;
private String classLoaderClass;
private boolean isRegEx = false;
private int expand = 1;
@@ -77,6 +81,12 @@ public class GetStaticCommand extends AnnotatedCommand {
this.hashCode = hashCode;
}
@Option(longName = "classLoaderClass")
@Description("The class name of the special class's classLoader.")
public void setClassLoaderClass(String classLoaderClass) {
this.classLoaderClass = classLoaderClass;
}
@Option(shortName = "E", longName = "regex", flag = true)
@Description("Enable regular expression to match (wildcard matching by default)")
public void setRegEx(boolean regEx) {
@@ -93,6 +103,25 @@ public class GetStaticCommand extends AnnotatedCommand {
public void process(CommandProcess process) {
RowAffect affect = new RowAffect();
Instrumentation inst = process.session().getInstrumentation();
if (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);
GetStaticModel getStaticModel = new GetStaticModel()
.setClassLoaderClass(classLoaderClass)
.setMatchedClassLoaders(classLoaderVOList);
process.appendResult(getStaticModel);
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;
}
}
Set<Class<?>> matchedClasses = SearchUtils.searchClassOnly(inst, classPattern, isRegEx, hashCode);
try {
if (matchedClasses == null || matchedClasses.isEmpty()) {
@@ -4,6 +4,7 @@ import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.model.ClassVO;
import com.taobao.arthas.core.command.model.ClassLoaderVO;
import com.taobao.arthas.core.command.model.JadModel;
import com.taobao.arthas.core.command.model.MessageModel;
import com.taobao.arthas.core.command.model.RowAffectModel;
@@ -13,6 +14,7 @@ import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.shell.command.ExitStatus;
import com.taobao.arthas.core.util.ClassUtils;
import com.taobao.arthas.core.util.ClassLoaderUtils;
import com.taobao.arthas.core.util.CommandUtils;
import com.taobao.arthas.core.util.Decompiler;
import com.taobao.arthas.core.util.InstrumentationUtils;
@@ -30,6 +32,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Collection;
import java.util.regex.Pattern;
/**
@@ -52,6 +55,7 @@ public class JadCommand extends AnnotatedCommand {
private String classPattern;
private String methodName;
private String code = null;
private String classLoaderClass;
private boolean isRegEx = false;
private boolean hideUnicode = false;
@@ -79,6 +83,12 @@ public class JadCommand extends AnnotatedCommand {
this.code = code;
}
@Option(longName = "classLoaderClass")
@Description("The class name of the special class's classLoader.")
public void setClassLoaderClass(String classLoaderClass) {
this.classLoaderClass = classLoaderClass;
}
@Option(shortName = "E", longName = "regex", flag = true)
@Description("Enable regular expression to match (wildcard matching by default)")
public void setRegEx(boolean regEx) {
@@ -101,6 +111,25 @@ public class JadCommand extends AnnotatedCommand {
public void process(CommandProcess process) {
RowAffect affect = new RowAffect();
Instrumentation inst = process.session().getInstrumentation();
if (code == null && classLoaderClass != null) {
List<ClassLoader> matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst, classLoaderClass);
if (matchedClassLoaders.size() == 1) {
code = Integer.toHexString(matchedClassLoaders.get(0).hashCode());
} else if (matchedClassLoaders.size() > 1) {
Collection<ClassLoaderVO> classLoaderVOList = ClassUtils.createClassLoaderVOList(matchedClassLoaders);
JadModel jadModel = new JadModel()
.setClassLoaderClass(classLoaderClass)
.setMatchedClassLoaders(classLoaderVOList);
process.appendResult(jadModel);
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;
}
}
Set<Class<?>> matchedClasses = SearchUtils.searchClassOnly(inst, classPattern, isRegEx, code);
try {
@@ -7,6 +7,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Collection;
import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
@@ -14,12 +15,15 @@ import com.taobao.arthas.compiler.DynamicCompiler;
import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.model.MemoryCompilerModel;
import com.taobao.arthas.core.command.model.RowAffectModel;
import com.taobao.arthas.core.command.model.ClassLoaderVO;
import com.taobao.arthas.core.shell.cli.Completion;
import com.taobao.arthas.core.shell.cli.CompletionUtils;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.ClassLoaderUtils;
import com.taobao.arthas.core.util.FileUtils;
import com.taobao.arthas.core.util.ClassUtils;
import com.taobao.arthas.core.util.ClassLoaderUtils;
import com.taobao.arthas.core.util.affect.RowAffect;
import com.taobao.middleware.cli.annotations.Argument;
import com.taobao.middleware.cli.annotations.Description;
@@ -43,6 +47,7 @@ public class MemoryCompilerCommand extends AnnotatedCommand {
private String directory;
private String hashCode;
private String classLoaderClass;
private String encoding;
private List<String> sourcefiles;
@@ -59,6 +64,12 @@ public class MemoryCompilerCommand extends AnnotatedCommand {
this.hashCode = hashCode;
}
@Option(longName = "classLoaderClass")
@Description("The class name of the special class's classLoader.")
public void setClassLoaderClass(String classLoaderClass) {
this.classLoaderClass = classLoaderClass;
}
@Option(longName = "encoding")
@Description("Source file encoding")
public void setEncoding(String encoding) {
@@ -77,6 +88,25 @@ public class MemoryCompilerCommand extends AnnotatedCommand {
try {
Instrumentation inst = process.session().getInstrumentation();
if (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);
MemoryCompilerModel memoryCompilerModel = new MemoryCompilerModel()
.setClassLoaderClass(classLoaderClass)
.setMatchedClassLoaders(classLoaderVOList);
process.appendResult(memoryCompilerModel);
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;
}
}
ClassLoader classloader = null;
if (hashCode == null) {
classloader = ClassLoader.getSystemClassLoader();
@@ -9,16 +9,20 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import com.alibaba.arthas.deps.org.objectweb.asm.ClassReader;
import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.model.RedefineModel;
import com.taobao.arthas.core.command.model.ClassLoaderVO;
import com.taobao.arthas.core.shell.cli.Completion;
import com.taobao.arthas.core.shell.cli.CompletionUtils;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.ClassUtils;
import com.taobao.arthas.core.util.ClassLoaderUtils;
import com.taobao.middleware.cli.annotations.Argument;
import com.taobao.middleware.cli.annotations.Description;
import com.taobao.middleware.cli.annotations.Name;
@@ -42,6 +46,7 @@ public class RedefineCommand extends AnnotatedCommand {
private static final int MAX_FILE_SIZE = 10 * 1024 * 1024;
private String hashCode;
private String classLoaderClass;
private List<String> paths;
@@ -51,6 +56,12 @@ public class RedefineCommand extends AnnotatedCommand {
this.hashCode = hashCode;
}
@Option(longName = "classLoaderClass")
@Description("The class name of the special class's classLoader.")
public void setClassLoaderClass(String classLoaderClass) {
this.classLoaderClass = classLoaderClass;
}
@Argument(argName = "classfilePaths", index = 0)
@Description(".class file paths")
public void setPaths(List<String> paths) {
@@ -112,6 +123,25 @@ public class RedefineCommand extends AnnotatedCommand {
List<ClassDefinition> definitions = new ArrayList<ClassDefinition>();
for (Class<?> clazz : inst.getAllLoadedClasses()) {
if (bytesMap.containsKey(clazz.getName())) {
if (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);
RedefineModel classredefineModel = new RedefineModel()
.setClassLoaderClass(classLoaderClass)
.setMatchedClassLoaders(classLoaderVOList);
process.appendResult(classredefineModel);
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;
}
}
ClassLoader classLoader = clazz.getClassLoader();
if (classLoader != null && hashCode != null && !Integer.toHexString(classLoader.hashCode()).equals(hashCode)) {
continue;
@@ -11,6 +11,8 @@ public class DumpClassModel extends ResultModel {
private List<DumpClassVO> dumpedClasses;
private Collection<ClassVO> matchedClasses;
private Collection<ClassLoaderVO> matchedClassLoaders;
private String classLoaderClass;
public DumpClassModel() {
}
@@ -38,4 +40,22 @@ public class DumpClassModel extends ResultModel {
return this;
}
public String getClassLoaderClass() {
return classLoaderClass;
}
public DumpClassModel setClassLoaderClass(String classLoaderClass) {
this.classLoaderClass = classLoaderClass;
return this;
}
public Collection<ClassLoaderVO> getMatchedClassLoaders() {
return matchedClassLoaders;
}
public DumpClassModel setMatchedClassLoaders(Collection<ClassLoaderVO> matchedClassLoaders) {
this.matchedClassLoaders = matchedClassLoaders;
return this;
}
}
@@ -1,6 +1,7 @@
package com.taobao.arthas.core.command.model;
import java.util.Collection;
import java.util.List;
/**
* Data model of GetStaticCommand
@@ -11,6 +12,8 @@ public class GetStaticModel extends ResultModel {
private Collection<ClassVO> matchedClasses;
private ObjectVO field;
private int expand;
private Collection<ClassLoaderVO> matchedClassLoaders;
private String classLoaderClass;
public GetStaticModel() {
}
@@ -48,6 +51,24 @@ public class GetStaticModel extends ResultModel {
this.expand = expand;
}
public String getClassLoaderClass() {
return classLoaderClass;
}
public GetStaticModel setClassLoaderClass(String classLoaderClass) {
this.classLoaderClass = classLoaderClass;
return this;
}
public Collection<ClassLoaderVO> getMatchedClassLoaders() {
return matchedClassLoaders;
}
public GetStaticModel setMatchedClassLoaders(Collection<ClassLoaderVO> matchedClassLoaders) {
this.matchedClassLoaders = matchedClassLoaders;
return this;
}
@Override
public String getType() {
return "getstatic";
@@ -1,6 +1,7 @@
package com.taobao.arthas.core.command.model;
import java.util.Collection;
import java.util.List;
/**
* @author gongdewei 2020/4/22
@@ -9,6 +10,8 @@ public class JadModel extends ResultModel {
private ClassVO classInfo;
private String location;
private String source;
private Collection<ClassLoaderVO> matchedClassLoaders;
private String classLoaderClass;
//match multiple classes
private Collection<ClassVO> matchedClasses;
@@ -52,4 +55,22 @@ public class JadModel extends ResultModel {
public void setMatchedClasses(Collection<ClassVO> matchedClasses) {
this.matchedClasses = matchedClasses;
}
public String getClassLoaderClass() {
return classLoaderClass;
}
public JadModel setClassLoaderClass(String classLoaderClass) {
this.classLoaderClass = classLoaderClass;
return this;
}
public Collection<ClassLoaderVO> getMatchedClassLoaders() {
return matchedClassLoaders;
}
public JadModel setMatchedClassLoaders(Collection<ClassLoaderVO> matchedClassLoaders) {
this.matchedClassLoaders = matchedClassLoaders;
return this;
}
}
@@ -1,5 +1,6 @@
package com.taobao.arthas.core.command.model;
import java.util.Collection;
import java.util.List;
/**
@@ -8,6 +9,8 @@ import java.util.List;
public class MemoryCompilerModel extends ResultModel {
private List<String> files;
private Collection<ClassLoaderVO> matchedClassLoaders;
private String classLoaderClass;
public MemoryCompilerModel() {
}
@@ -24,6 +27,24 @@ public class MemoryCompilerModel extends ResultModel {
return files;
}
public String getClassLoaderClass() {
return classLoaderClass;
}
public MemoryCompilerModel setClassLoaderClass(String classLoaderClass) {
this.classLoaderClass = classLoaderClass;
return this;
}
public Collection<ClassLoaderVO> getMatchedClassLoaders() {
return matchedClassLoaders;
}
public MemoryCompilerModel setMatchedClassLoaders(Collection<ClassLoaderVO> matchedClassLoaders) {
this.matchedClassLoaders = matchedClassLoaders;
return this;
}
@Override
public String getType() {
return "mc";
@@ -1,6 +1,7 @@
package com.taobao.arthas.core.command.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
@@ -11,6 +12,8 @@ public class RedefineModel extends ResultModel {
private int redefinitionCount;
private List<String> redefinedClasses;
private Collection<ClassLoaderVO> matchedClassLoaders;
private String classLoaderClass;
public RedefineModel() {
redefinedClasses = new ArrayList<String>();
@@ -37,6 +40,24 @@ public class RedefineModel extends ResultModel {
this.redefinedClasses = redefinedClasses;
}
public String getClassLoaderClass() {
return classLoaderClass;
}
public RedefineModel setClassLoaderClass(String classLoaderClass) {
this.classLoaderClass = classLoaderClass;
return this;
}
public Collection<ClassLoaderVO> getMatchedClassLoaders() {
return matchedClassLoaders;
}
public RedefineModel setMatchedClassLoaders(Collection<ClassLoaderVO> matchedClassLoaders) {
this.matchedClassLoaders = matchedClassLoaders;
return this;
}
@Override
public String getType() {
return "redefine";
@@ -23,6 +23,12 @@ public class DumpClassView extends ResultView<DumpClassModel> {
@Override
public void draw(CommandProcess process, DumpClassModel result) {
if (result.getMatchedClassLoaders() != null) {
process.write("Matched classloaders: \n");
ClassLoaderView.drawClassLoaders(process, result.getMatchedClassLoaders(), false);
process.write("\n");
return;
}
if (result.getDumpedClasses() != null) {
drawDumpedClasses(process, result.getDumpedClasses());
@@ -16,6 +16,12 @@ public class GetStaticView extends ResultView<GetStaticModel> {
@Override
public void draw(CommandProcess process, GetStaticModel result) {
if (result.getMatchedClassLoaders() != null) {
process.write("Matched classloaders: \n");
ClassLoaderView.drawClassLoaders(process, result.getMatchedClassLoaders(), false);
process.write("\n");
return;
}
int expand = result.getExpand();
if (result.getField() != null) {
ObjectVO field = result.getField();
@@ -19,6 +19,12 @@ public class JadView extends ResultView<JadModel> {
@Override
public void draw(CommandProcess process, JadModel result) {
if (result.getMatchedClassLoaders() != null) {
process.write("Matched classloaders: \n");
ClassLoaderView.drawClassLoaders(process, result.getMatchedClassLoaders(), false);
process.write("\n");
return;
}
if (result.getMatchedClasses() != null) {
Element table = ClassUtils.renderMatchedClasses(result.getMatchedClasses());
@@ -9,6 +9,12 @@ import com.taobao.arthas.core.shell.command.CommandProcess;
public class MemoryCompilerView extends ResultView<MemoryCompilerModel> {
@Override
public void draw(CommandProcess process, MemoryCompilerModel result) {
if (result.getMatchedClassLoaders() != null) {
process.write("Matched classloaders: \n");
ClassLoaderView.drawClassLoaders(process, result.getMatchedClassLoaders(), false);
process.write("\n");
return;
}
process.write("Memory compiler output:\n");
for (String file : result.getFiles()) {
process.write(file + '\n');
@@ -10,6 +10,12 @@ public class RedefineView extends ResultView<RedefineModel> {
@Override
public void draw(CommandProcess process, RedefineModel result) {
if (result.getMatchedClassLoaders() != null) {
process.write("Matched classloaders: \n");
ClassLoaderView.drawClassLoaders(process, result.getMatchedClassLoaders(), false);
process.write("\n");
return;
}
StringBuilder sb = new StringBuilder();
for (String aClass : result.getRedefinedClasses()) {
sb.append(aClass).append("\n");
+25
View File
@@ -11,6 +11,7 @@ dump
|---:|:---|
|*class-pattern*|类名表达式匹配|
|`[c:]`|类所属 ClassLoader 的 hashcode|
|`[classLoaderClass:]`|指定执行表达式的 ClassLoader 的 class name|
|`[d:]`|设置类文件的目标目录|
|[E]|开启正则表达式匹配,默认为通配符匹配|
@@ -37,3 +38,27 @@ $ dump -d /tmp/output java.lang.String
null /tmp/output/java/lang/String.class
Affect(row-cnt:1) cost in 138 ms.
```
* 指定classLoader
注意hashcode是变化的,需要先查看当前的ClassLoader信息,提取对应ClassLoader的hashcode。
如果你使用`-c`,你需要手动输入hashcode`-c <hashcode>`
```bash
$ dump -c 3d4eac69 demo.*
```
对于只有唯一实例的ClassLoader可以通过`--classLoaderClass`指定class name,使用起来更加方便:
```bash
$ dump --classLoaderClass sun.misc.Launcher$AppClassLoader demo.*
HASHCODE CLASSLOADER LOCATION
3d4eac69 +-sun.misc.Launcher$AppClassLoader@3d4eac69 /Users/admin/logs/arthas/classdump/sun.misc.Launcher$AppClassLoader-3d4eac69/demo/MathGame.class
+-sun.misc.Launcher$ExtClassLoader@66350f69
Affect(row-cnt:1) cost in 39 ms.
```
* 注: 这里classLoaderClass 在 java 8 是 sun.misc.Launcher$AppClassLoader,而java 11的classloader是jdk.internal.loader.ClassLoaders$AppClassLoaderkatacoda目前环境是java8。
`--classLoaderClass` 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而`-c <hashcode>`是动态变化的。
+25
View File
@@ -11,6 +11,7 @@ dump
|---:|:---|
|*class-pattern*|class name pattern|
|`[c:]`|hashcode of the [class loader](classloader.md) that loaded the target class|
|`[classLoaderClass:]`| The class name of the ClassLoader that executes the expression. |
|`[d:]`|set the destination directory for class files|
|`[E]`|turn on regex match, the default behavior is wild card match|
@@ -37,3 +38,27 @@ $ dump -d /tmp/output java.lang.String
null /tmp/output/java/lang/String.class
Affect(row-cnt:1) cost in 138 ms.
```
* Specify classLoader
Note that the hashcode changes, you need to check the current ClassLoader information first, and extract the hashcode corresponding to the ClassLoader.
if you use`-c`, you have to manually type hashcode by `-c <hashcode>`.
```bash
$ dump -c 3d4eac69 demo.*
```
For classloader with only one instance, it can be specified by `--classLoaderClass` using class name, which is more convenient to use.
```bash
$ dump --classLoaderClass sun.misc.Launcher$AppClassLoader demo.*
HASHCODE CLASSLOADER LOCATION
3d4eac69 +-sun.misc.Launcher$AppClassLoader@3d4eac69 /Users/admin/logs/arthas/classdump/sun.misc.Launcher$AppClassLoader-3d4eac69/demo/MathGame.class
+-sun.misc.Launcher$ExtClassLoader@66350f69
Affect(row-cnt:1) cost in 39 ms.
```
* PS: Here the classLoaderClass in java 8 is sun.misc.Launcher$AppClassLoader, while in java 11 it's jdk.internal.loader.ClassLoaders$AppClassLoader. Currently katacoda using java 8.
The value of `--classloaderclass` is the class name of classloader. It can only work when it matches a unique classloader instance. The purpose is to facilitate the input of general commands. However, `-c <hashcode>` is dynamic.
+17
View File
@@ -29,6 +29,23 @@ field: random
]
```
* Specify classLoader
Note that the hashcode changes, you need to check the current ClassLoader information first, and extract the hashcode corresponding to the ClassLoader using `sc -d <ClassName>`.
if you use`-c`, you have to manually type hashcode by `-c <hashcode>`.
```bash
$ getstatic -c 3d4eac69 demo.MathGame random
```
For classloader with only one instance, it can be specified by `--classLoaderClass` using class name, which is more convenient to use.
`getstatic --classLoaderClass demo.MathGame random`
* PS: Here the classLoaderClass in java 8 is sun.misc.Launcher$AppClassLoader, while in java 11 it's jdk.internal.loader.ClassLoaders$AppClassLoader. Currently katacoda using java 8.
The value of `--classloaderclass` is the class name of classloader. It can only work when it matches a unique classloader instance. The purpose is to facilitate the input of general commands. However, `-c <hashcode>` is dynamic.
Tip: if the static field is a complex class, you can even use [`OGNL`](https://commons.apache.org/proper/commons-ognl/language-guide.html) to traverse, filter and access the inner properties of this class.
+5
View File
@@ -16,6 +16,7 @@ jad
|---:|:---|
|*class-pattern*|pattern for the class name|
|`[c:]`|hashcode of the class loader that loads the class|
|`[classLoaderClass:]`| The class name of the ClassLoader that executes the expression. |
|`[E]`|turn on regex match while the default is wildcard match|
### Usage
@@ -143,3 +144,7 @@ public class Logger extends Category
Affect(row-cnt:1) cost in 190 ms.
```
For classloader with only one instance, it can be specified by `--classLoaderClass` using class name, which is more convenient to use.
The value of `--classloaderclass` is the class name of classloader. It can only work when it matches a unique classloader instance. The purpose is to facilitate the input of general commands. However, `-c <hashcode>` is dynamic.
+3 -3
View File
@@ -144,11 +144,11 @@ The value of `--classloaderclass` is the class name of classloader. It can only
update logger level success.
```
#### 指定classloader更新 logger level
#### Speecify classloader to update logger level
默认情况下,logger命令会在SystemClassloader下执行,如果应用是传统的`war`应用,或者spring boot fat jar启动的应用,那么需要指定classloader。
By defaultlogger command will be executed under SystemClassloader, if the application is a traditional `war`, or using spring boot fat jar, then it needs to specify classloader。
可以先用 `sc -d yourClassName` 来查看具体的 classloader hashcode然后在更新level时指定classloader
You can first use `sc -d yourClassName` to check specified classloader hashcodethen specify classloader when updating logger level:
```bash
[arthas@2062]$ logger -c 2a139a55 --name ROOT --level debug
+9
View File
@@ -15,6 +15,15 @@ The classloader can be specified with the `-c` option:
mc -c 327a647b /tmp/Test.java
```
You can also specify the ClassLoader with the `--classLoaderClass` option:
```bash
$ mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp
Memory compiler output:
/tmp/com/example/demo/arthas/user/UserController.class
Affect(row-cnt:1) cost in 346 ms
```
The output directory can be specified with the `-d` option:
```bash
+3 -1
View File
@@ -28,6 +28,7 @@ Reference: [Instrumentation#redefineClasses](https://docs.oracle.com/javase/8/do
|Name|Specification|
|---:|:---|
|`[c:]`|hashcode of the class loader|
|`[classLoaderClass:]`| The class name of the ClassLoader that executes the expression. |
|`[p:]`|absolute path of the external `*.class`, multiple paths are separated with 'space'|
@@ -35,7 +36,8 @@ Reference: [Instrumentation#redefineClasses](https://docs.oracle.com/javase/8/do
```bash
redefine /tmp/Test.class
redefine -c 327a647b /tmp/Test.class /tmp/Test$Inner.class
redefine -c 327a647b /tmp/Test.class /tmp/Test\$Inner.class
redefine --classLoaderClass sun.misc.Launcher$AppClassLoader /tmp/Test.class /tmp/Test\$Inner.class
```
### Use with the jad/mc command
+19
View File
@@ -30,6 +30,25 @@ field: random
]
```
* 指定classLoader
注意hashcode是变化的,需要先查看当前的ClassLoader信息,使用`sc -d <ClassName>`提取对应ClassLoader的hashcode。
如果你使用`-c`,你需要手动输入hashcode`-c <hashcode>`
```bash
$ getstatic -c 3d4eac69 demo.MathGame random
```
对于只有唯一实例的ClassLoader可以通过`--classLoaderClass`指定class name,使用起来更加方便:
`getstatic --classLoaderClass sun.misc.Launcher$AppClassLoader demo.MathGame random`
* 注: 这里classLoaderClass 在 java 8 是 sun.misc.Launcher$AppClassLoader,而java 11的classloader是jdk.internal.loader.ClassLoaders$AppClassLoaderkatacoda目前环境是java8。
`--classLoaderClass` 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而`-c <hashcode>`是动态变化的。
如果该静态属性是一个复杂对象,还可以支持在该属性上通过ognl表示进行遍历,过滤,访问对象的内部属性等操作。
* OGNL特殊用法请参考:[https://github.com/alibaba/arthas/issues/71](https://github.com/alibaba/arthas/issues/71)
+4
View File
@@ -16,6 +16,7 @@ jad
|---:|:---|
|*class-pattern*|类名表达式匹配|
|`[c:]`|类所属 ClassLoader 的 hashcode|
|`[classLoaderClass:]`|指定执行表达式的 ClassLoader 的 class name|
|[E]|开启正则表达式匹配,默认为通配符匹配|
### 使用参考
@@ -144,3 +145,6 @@ public class Logger extends Category
Affect(row-cnt:1) cost in 190 ms.
```
对于只有唯一实例的ClassLoader还可以通过`--classLoaderClass`指定class name,使用起来更加方便:
`--classLoaderClass` 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而`-c <hashcode>`是动态变化的。
+9
View File
@@ -15,6 +15,15 @@ mc /tmp/Test.java
mc -c 327a647b /tmp/Test.java
```
也可以通过`--classLoaderClass`参数指定ClassLoader
```bash
$ mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp
Memory compiler output:
/tmp/com/example/demo/arthas/user/UserController.class
Affect(row-cnt:1) cost in 346 ms
```
可以通过`-d`命令指定输出目录:
```bash
+2
View File
@@ -27,6 +27,7 @@ redefine
|参数名称|参数说明|
|---:|:---|
|[c:]|ClassLoader的hashcode|
|`[classLoaderClass:]`|指定执行表达式的 ClassLoader 的 class name|
|[p:]|外部的`.class`文件的完整路径,支持多个|
@@ -36,6 +37,7 @@ redefine
```bash
redefine /tmp/Test.class
redefine -c 327a647b /tmp/Test.class /tmp/Test\$Inner.class
redefine --classLoaderClass sun.misc.Launcher$AppClassLoader /tmp/Test.class /tmp/Test\$Inner.class
```
### 结合 jad/mc 命令使用
@@ -47,21 +47,25 @@ $ sc -d *UserController | grep classLoaderHash
请记下你的classLoaderHash,后面需要使用它。在这里,它是 `1be6f5c3`
注意:请使用你的classLoaderHash值覆盖 `<classLoaderHash>` ,然后手动执行这些命令:
### mc
保存好`/tmp/UserController.java`之后,使用`mc`(Memory Compiler)命令来编译,并且通过`-c`参数指定ClassLoader
保存好`/tmp/UserController.java`之后,使用`mc`(Memory Compiler)命令来编译,并且通过`-c`或者`--classLoaderClass`参数指定ClassLoader
`mc -c <classLoaderHash> /tmp/UserController.java -d /tmp`
`mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp`{{execute T2}}
```bash
$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp
$ mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp
Memory compiler output:
/tmp/com/example/demo/arthas/user/UserController.class
Affect(row-cnt:1) cost in 346 ms
```
也可以通过`mc -c <classLoaderHash> /tmp/UserController.java -d /tmp`,使用`-c`参数指定ClassLoaderHash:
```bash
$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp
```
### redefine
再使用`redefine`命令重新加载新编译好的`UserController.class`
@@ -48,21 +48,25 @@ It can be found that it is loaded by spring boot `LaunchedURLClassLoader@1be6f5c
Please write down your classLoaderHash here, in the case here, it's `1be6f5c3`. It will be used in the future steps.
Note: Please replace `<classLoaderHash>` with your classLoaderHash above, then execute the related commands manually in the following steps:
### mc
After saving `/tmp/UserController.java`, compile with the `mc` (Memory Compiler) command and specify the ClassLoader with the `-c` option:
After saving `/tmp/UserController.java`, compile with the `mc` (Memory Compiler) command and specify the ClassLoader with the `-c` or `--classLoaderClass` option:
`mc -c <classLoaderHash> /tmp/UserController.java -d /tmp`
`mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp`{{execute T2}}
```bash
$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp
$ mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp
Memory compiler output:
/tmp/com/example/demo/arthas/user/UserController.class
Affect(row-cnt:1) cost in 346 ms
```
You can also execute `mc -c <classLoaderHash> /tmp/UserController.java -d /tmp`using `-c` to specify ClassLoaderHash:
```bash
$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp
```
### redefine
Then reload the newly compiled `UserController.class` with the `redefine` command:
@@ -45,23 +45,33 @@ $ sc -d *UserController | grep classLoaderHash
可以发现是 spring boot `LaunchedURLClassLoader@1be6f5c3` 加载的。
请记下你的classLoaderHash,后面需要使用它。在这里,它是 `1be6f5c3`
注意hashcode是变化的,需要先查看当前的ClassLoader信息,提取对应ClassLoader的hashcode
注意:请使用你的classLoaderHash值覆盖 `<classLoaderHash>` ,然后手动执行下面所有所述命令:
如果你使用`-c`,你需要手动输入hashcode`-c <hashcode>`
对于只有唯一实例的ClassLoader可以通过`--classLoaderClass`指定class name,使用起来更加方便.
`--classLoaderClass` 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而`-c <hashcode>`是动态变化的。
### mc
保存好`/tmp/UserController.java`之后,使用`mc`(Memory Compiler)命令来编译,并且通过`-c`参数指定ClassLoader
保存好`/tmp/UserController.java`之后,使用`mc`(Memory Compiler)命令来编译,并且通过`--classLoaderClass`参数指定ClassLoader
`mc -c <classLoaderHash> /tmp/UserController.java -d /tmp`
`mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp`{{execute T2}}
```bash
$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp
$ mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp
Memory compiler output:
/tmp/com/example/demo/arthas/user/UserController.class
Affect(row-cnt:1) cost in 346 ms
```
也可以通过`mc -c <classLoaderHash> /tmp/UserController.java -d /tmp`,使用`-c`参数指定ClassLoaderHash:
```bash
$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp
```
### redefine
再使用`redefine`命令重新加载新编译好的`UserController.class`
@@ -46,23 +46,33 @@ $ sc -d *UserController | grep classLoaderHash
It can be found that it is loaded by spring boot `LaunchedURLClassLoader@1be6f5c3`.
Please write down your classLoaderHash here, in the case here, it's `1be6f5c3`. It will be used in the future steps.
Note that the hashcode changes, you need to check the current ClassLoader information first, and extract the hashcode corresponding to the ClassLoader.
Note: Please replace `<classLoaderHash>` with your classLoaderHash above, then execute the commands manually in the following steps:
if you use`-c`, you have to manually type hashcode by `-c <hashcode>`.
For classloader with only one instance, it can be specified by `--classLoaderClass` using class name, which is more convenient to use.
The value of `--classloaderclass` is the class name of classloader. It can only work when it matches a unique classloader instance. The purpose is to facilitate the input of general commands. However, `-c <hashcode>` is dynamic.
### mc
After saving `/tmp/UserController.java`, compile with the `mc` (Memory Compiler) command and specify the ClassLoader with the `-c` option:
After saving `/tmp/UserController.java`, compile with the `mc` (Memory Compiler) command and specify the ClassLoader with the `--classLoaderClass` option:
`mc -c <classLoaderHash> /tmp/UserController.java -d /tmp`
`mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp`{{execute T2}}
```bash
$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp
$ mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp
Memory compiler output:
/tmp/com/example/demo/arthas/user/UserController.class
Affect(row-cnt:1) cost in 346 ms
```
You can also execute `mc -c <classLoaderHash> /tmp/UserController.java -d /tmp`using `-c` to specify ClassLoaderHash:
```bash
$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp
```
### redefine
Then reload the newly compiled `UserController.class` with the `redefine` command:
@@ -8,6 +8,7 @@
|*class-pattern*|类名表达式匹配|
|`[c:]`|类所属 ClassLoader 的 hashcode|
|`[d:]`|设置类文件的目标目录|
|`[classLoaderClass:]`|指定执行表达式的 ClassLoader 的 class name|
|[E]|开启正则表达式匹配,默认为通配符匹配|
### 使用参考
@@ -39,3 +40,29 @@ $ dump -d /tmp/output java.lang.String
null /tmp/output/java/lang/String.class
Affect(row-cnt:1) cost in 138 ms.
```
* 指定classLoader
注意hashcode是变化的,需要先查看当前的ClassLoader信息,提取对应ClassLoader的hashcode。
如果你使用`-c`,你需要手动输入hashcode`-c <hashcode>`
```bash
$ dump -c 3d4eac69 demo.*
```
对于只有唯一实例的ClassLoader可以通过`--classLoaderClass`指定class name,使用起来更加方便:
`dump --classLoaderClass sun.misc.Launcher$AppClassLoader demo.*`{{execute T2}}
```bash
$ dump --classLoaderClass sun.misc.Launcher$AppClassLoader demo.*
HASHCODE CLASSLOADER LOCATION
3d4eac69 +-sun.misc.Launcher$AppClassLoader@3d4eac69 /Users/admin/logs/arthas/classdump/sun.misc.Launcher$AppClassLoader-3d4eac69/demo/MathGame.class
+-sun.misc.Launcher$ExtClassLoader@66350f69
Affect(row-cnt:1) cost in 39 ms.
```
* 注: 这里classLoaderClass 在 java 8 是 sun.misc.Launcher$AppClassLoader,而java 11的classloader是jdk.internal.loader.ClassLoaders$AppClassLoaderkatacoda目前环境是java8。
`--classLoaderClass` 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而`-c <hashcode>`是动态变化的。
@@ -7,6 +7,7 @@
|---:|:---|
|*class-pattern*|class name pattern|
|`[c:]`|hashcode of the [class loader](classloader.md) that loaded the target class|
|`[classLoaderClass:]`| The class name of the ClassLoader that executes the expression. |
|`[d:]`|set the destination directory for class files|
|`[E]`|turn on regex match, the default behavior is wild card match|
@@ -39,3 +40,29 @@ $ dump
null /tmp/output/java/lang/String.class
Affect(row-cnt:1) cost in 138 ms.
```
* Specify classLoader
Note that the hashcode changes, you need to check the current ClassLoader information first, and extract the hashcode corresponding to the ClassLoader.
if you use`-c`, you have to manually type hashcode by `-c <hashcode>`.
```bash
$ dump -c 3d4eac69 demo.*
```
For classloader with only one instance, it can be specified by `--classLoaderClass` using class name, which is more convenient to use.
`dump --classLoaderClass sun.misc.Launcher$AppClassLoader demo.*`{{execute T2}}
```bash
$ dump --classLoaderClass sun.misc.Launcher$AppClassLoader demo.*
HASHCODE CLASSLOADER LOCATION
3d4eac69 +-sun.misc.Launcher$AppClassLoader@3d4eac69 /Users/admin/logs/arthas/classdump/sun.misc.Launcher$AppClassLoader-3d4eac69/demo/MathGame.class
+-sun.misc.Launcher$ExtClassLoader@66350f69
Affect(row-cnt:1) cost in 39 ms.
```
* PS: Here the classLoaderClass in java 8 is sun.misc.Launcher$AppClassLoader, while in java 11 it's jdk.internal.loader.ClassLoaders$AppClassLoader. Currently katacoda using java 8.
The value of `--classloaderclass` is the class name of classloader. It can only work when it matches a unique classloader instance. The purpose is to facilitate the input of general commands. However, `-c <hashcode>` is dynamic.
@@ -28,6 +28,24 @@ field: random
]
```
* 指定classLoader
注意hashcode是变化的,需要先查看当前的ClassLoader信息,使用`sc -d <ClassName>`提取对应ClassLoader的hashcode。
如果你使用`-c`,你需要手动输入hashcode`-c <hashcode>`
```bash
$ getstatic -c 3d4eac69 demo.MathGame random
```
对于只有唯一实例的ClassLoader可以通过`--classLoaderClass`指定class name,使用起来更加方便:
`getstatic --classLoaderClass sun.misc.Launcher$AppClassLoader demo.MathGame random`{{execute T2}}
* 注: 这里classLoaderClass 在 java 8 是 sun.misc.Launcher$AppClassLoader,而java 11的classloader是jdk.internal.loader.ClassLoaders$AppClassLoaderkatacoda目前环境是java8。
`--classLoaderClass` 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而`-c <hashcode>`是动态变化的。
如果该静态属性是一个复杂对象,还可以支持在该属性上通过ognl表示进行遍历,过滤,访问对象的内部属性等操作。
* OGNL特殊用法请参考:[https://github.com/alibaba/arthas/issues/71](https://github.com/alibaba/arthas/issues/71)
@@ -27,6 +27,24 @@ field: random
]
```
* Specify classLoader
Note that the hashcode changes, you need to check the current ClassLoader information first, and extract the hashcode corresponding to the ClassLoader using `sc -d <ClassName>`.
if you use`-c`, you have to manually type hashcode by `-c <hashcode>`.
```bash
$ getstatic -c 3d4eac69 demo.MathGame random
```
For classloader with only one instance, it can be specified by `--classLoaderClass` using class name, which is more convenient to use.
`getstatic --classLoaderClass demo.MathGame random`{{execute T2}}
* PS: Here the classLoaderClass in java 8 is sun.misc.Launcher$AppClassLoader, while in java 11 it's jdk.internal.loader.ClassLoaders$AppClassLoader. Currently katacoda using java 8.
The value of `--classloaderclass` is the class name of classloader. It can only work when it matches a unique classloader instance. The purpose is to facilitate the input of general commands. However, `-c <hashcode>` is dynamic.
Tip: if the static field is a complex class, you can even use [`OGNL`](https://commons.apache.org/proper/commons-ognl/language-guide.html) to traverse, filter and access the inner properties of this class.
+4
View File
@@ -12,6 +12,7 @@
|---:|:---|
|*class-pattern*|类名表达式匹配|
|`[c:]`|类所属 ClassLoader 的 hashcode|
|`[classLoaderClass:]`|指定执行表达式的 ClassLoader 的 class name|
|[E]|开启正则表达式匹配,默认为通配符匹配|
### 使用参考
@@ -150,3 +151,6 @@ public class Logger extends Category
Affect(row-cnt:1) cost in 190 ms.
```
对于只有唯一实例的ClassLoader还可以通过`--classLoaderClass`指定class name,使用起来更加方便:
`--classLoaderClass` 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而`-c <hashcode>`是动态变化的。
+5
View File
@@ -12,6 +12,7 @@
|---:|:---|
|*class-pattern*|pattern for the class name|
|`[c:]`|hashcode of the class loader that loads the class|
|`[classLoaderClass:]`| The class name of the ClassLoader that executes the expression. |
|`[E]`|turn on regex match while the default is wildcard match|
### Usage
@@ -149,3 +150,7 @@ public class Logger extends Category
Affect(row-cnt:1) cost in 190 ms.
```
For classloader with only one instance, it can be specified by `--classLoaderClass` using class name, which is more convenient to use.
The value of `--classloaderclass` is the class name of classloader. It can only work when it matches a unique classloader instance. The purpose is to facilitate the input of general commands. However, `-c <hashcode>` is dynamic.
@@ -115,10 +115,10 @@ update logger level success.
可以先用 `sc -d yourClassName` 来查看具体的 classloader hashcode,然后在更新level时指定classloader
`logger -c <classLoaderHash> --name ROOT --level debug`
`logger --classLoaderClass sun.misc.Launcher$AppClassLoader --name ROOT --level debug`{{execute T2}}
```bash
[arthas@2062]$ logger -c 2a139a55 --name ROOT --level debug
[arthas@2062]$ logger --classLoaderClass sun.misc.Launcher$AppClassLoader --name ROOT --level debug
```
#### 查看没有appender的logger的信息
@@ -109,11 +109,11 @@ The value of `--classloaderclass` is the class name of classloader. It can only
update logger level success.
```
#### 指定classloader更新 logger level
#### Speecify classloader to update logger level
默认情况下,logger命令会在SystemClassloader下执行,如果应用是传统的`war`应用,或者spring boot fat jar启动的应用,那么需要指定classloader。
By defaultlogger command will be executed under SystemClassloader, if the application is a traditional `war`, or using spring boot fat jar, then it needs to specify classloader。
可以先用 `sc -d yourClassName` 来查看具体的 classloader hashcode然后在更新level时指定classloader
You can first use `sc -d yourClassName` to check specified classloader hashcodethen specify classloader when updating logger level:
`logger --classLoaderClass sun.misc.Launcher$AppClassLoader --name ROOT --level debug`{{execute T2}}
@@ -45,23 +45,33 @@ $ sc -d *UserController | grep classLoaderHash
可以发现是 spring boot `LaunchedURLClassLoader@1be6f5c3` 加载的。
请记下你的classLoaderHash,后面需要使用它。在这里,它是 `1be6f5c3`
注意hashcode是变化的,需要先查看当前的ClassLoader信息,提取对应ClassLoader的hashcode
注意:请使用你的classLoaderHash值覆盖 `<classLoaderHash>` ,然后手动执行下面所有所述命令:
如果你使用`-c`,你需要手动输入hashcode`-c <hashcode>`
对于只有唯一实例的ClassLoader可以通过`--classLoaderClass`指定class name,使用起来更加方便.
`--classLoaderClass` 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而`-c <hashcode>`是动态变化的。
### mc
保存好`/tmp/UserController.java`之后,使用`mc`(Memory Compiler)命令来编译,并且通过`-c`参数指定ClassLoader
保存好`/tmp/UserController.java`之后,使用`mc`(Memory Compiler)命令来编译,并且通过`--classLoaderClass`参数指定ClassLoader
`mc -c <classLoaderHash> /tmp/UserController.java -d /tmp`
`mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp`{{execute T2}}
```bash
$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp
$ mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp
Memory compiler output:
/tmp/com/example/demo/arthas/user/UserController.class
Affect(row-cnt:1) cost in 346 ms
```
也可以通过`mc -c <classLoaderHash> /tmp/UserController.java -d /tmp`,使用`-c`参数指定ClassLoaderHash:
```bash
$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp
```
### redefine
再使用`redefine`命令重新加载新编译好的`UserController.class`
@@ -2,6 +2,6 @@
> Memory Compiler/内存编译器,编译`.java`文件生成`.class`。
可以通过`-c`参数指定classloader`-d`参数指定输出目录
可以通过`-c`/`--classLoaderClass`参数指定classloader`-d`参数指定输出目录
编译生成`.class`文件之后,可以结合`redefine`命令实现热更新代码。
@@ -23,6 +23,7 @@
|参数名称|参数说明|
|---:|:---|
|[c:]|ClassLoader的hashcode|
|`[classLoaderClass:]`|指定执行表达式的 ClassLoader 的 class name|
|[p:]|外部的`.class`文件的完整路径,支持多个|
@@ -46,23 +46,33 @@ $ sc -d *UserController | grep classLoaderHash
It can be found that it is loaded by spring boot `LaunchedURLClassLoader@1be6f5c3`.
Please write down your classLoaderHash here, in the case here, it's `1be6f5c3`. It will be used in the future steps.
Note that the hashcode changes, you need to check the current ClassLoader information first, and extract the hashcode corresponding to the ClassLoader.
Note: Please replace `<classLoaderHash>` with your classLoaderHash above, then execute the commands manually in the following steps:
if you use`-c`, you have to manually type hashcode by `-c <hashcode>`.
For classloader with only one instance, it can be specified by `--classLoaderClass` using class name, which is more convenient to use.
The value of `--classloaderclass` is the class name of classloader. It can only work when it matches a unique classloader instance. The purpose is to facilitate the input of general commands. However, `-c <hashcode>` is dynamic.
### mc
After saving `/tmp/UserController.java`, compile with the `mc` (Memory Compiler) command and specify the ClassLoader with the `-c` option:
After saving `/tmp/UserController.java`, compile with the `mc` (Memory Compiler) command and specify the ClassLoader with the `--classLoaderClass` option:
`mc -c <classLoaderHash> /tmp/UserController.java -d /tmp`
`mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp`{{execute T2}}
```bash
$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp
$ mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp
Memory compiler output:
/tmp/com/example/demo/arthas/user/UserController.class
Affect(row-cnt:1) cost in 346 ms
```
You can also execute `mc -c <classLoaderHash> /tmp/UserController.java -d /tmp`using `-c` to specify ClassLoaderHash:
```bash
$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp
```
### redefine
Then reload the newly compiled `UserController.class` with the `redefine` command:
@@ -1,6 +1,6 @@
> Memory compiler, compiles `.java` files into `.class` files in memory.
The classloader can be specified with the `-c` option, the output directory can be specified with the `-d` option.
The classloader can be specified with the `-c`/`--classLoaderClass` option, the output directory can be specified with the `-d` option.
After compiling the `.class` file, you can use the [redefine](redefine.md) command to re-define the loaded classes in JVM.
After compiling the `.class` file, you can use the redefine command to re-define the loaded classes in JVM.
@@ -24,6 +24,7 @@ Reference: [Instrumentation#redefineClasses](https://docs.oracle.com/javase/8/do
|Name|Specification|
|---:|:---|
|`[c:]`|hashcode of the class loader|
|`[classLoaderClass:]`| The class name of the ClassLoader that executes the expression. |
|`[p:]`|absolute path of the external `*.class`, multiple paths are separated with 'space'|
### Restrictions of the redefine command