diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java index 2e9f2931d..0f1724dbe 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java @@ -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 matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst, classLoaderClass); + if (matchedClassLoaders.size() == 1) { + code = Integer.toHexString(matchedClassLoaders.get(0).hashCode()); + } else if (matchedClassLoaders.size() > 1) { + Collection 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 '"); + return; + } else { + process.end(-1, "Can not find classloader by class name: " + classLoaderClass + "."); + return; + } + } + Set> matchedClasses = SearchUtils.searchClass(inst, classPattern, isRegEx, code); if (matchedClasses == null || matchedClasses.isEmpty()) { status = processNoMatch(process); diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java index e008fd468..93ca30ce4 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java @@ -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 matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst, classLoaderClass); + if (matchedClassLoaders.size() == 1) { + hashCode = Integer.toHexString(matchedClassLoaders.get(0).hashCode()); + } else if (matchedClassLoaders.size() > 1) { + Collection 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 '"); + return; + } else { + process.end(-1, "Can not find classloader by class name: " + classLoaderClass + "."); + return; + } + } + Set> matchedClasses = SearchUtils.searchClassOnly(inst, classPattern, isRegEx, hashCode); try { if (matchedClasses == null || matchedClasses.isEmpty()) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java index cbb6ef955..ce62103e0 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java @@ -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 matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst, classLoaderClass); + if (matchedClassLoaders.size() == 1) { + code = Integer.toHexString(matchedClassLoaders.get(0).hashCode()); + } else if (matchedClassLoaders.size() > 1) { + Collection 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 '"); + return; + } else { + process.end(-1, "Can not find classloader by class name: " + classLoaderClass + "."); + return; + } + } + Set> matchedClasses = SearchUtils.searchClassOnly(inst, classPattern, isRegEx, code); try { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java index c252f939f..85a515a37 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java @@ -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 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 matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst, classLoaderClass); + if (matchedClassLoaders.size() == 1) { + hashCode = Integer.toHexString(matchedClassLoaders.get(0).hashCode()); + } else if (matchedClassLoaders.size() > 1) { + Collection 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 '"); + return; + } else { + process.end(-1, "Can not find classloader by class name: " + classLoaderClass + "."); + return; + } + } + ClassLoader classloader = null; if (hashCode == null) { classloader = ClassLoader.getSystemClassLoader(); diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java index 8a7595b43..60ac3762d 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java @@ -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 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 paths) { @@ -112,6 +123,25 @@ public class RedefineCommand extends AnnotatedCommand { List definitions = new ArrayList(); for (Class clazz : inst.getAllLoadedClasses()) { if (bytesMap.containsKey(clazz.getName())) { + + if (hashCode == null && classLoaderClass != null) { + List matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst, classLoaderClass); + if (matchedClassLoaders.size() == 1) { + hashCode = Integer.toHexString(matchedClassLoaders.get(0).hashCode()); + } else if (matchedClassLoaders.size() > 1) { + Collection 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 '"); + 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; diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/DumpClassModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/DumpClassModel.java index e7b8bd684..6dd02229b 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/model/DumpClassModel.java +++ b/core/src/main/java/com/taobao/arthas/core/command/model/DumpClassModel.java @@ -11,6 +11,8 @@ public class DumpClassModel extends ResultModel { private List dumpedClasses; private Collection matchedClasses; + private Collection 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 getMatchedClassLoaders() { + return matchedClassLoaders; + } + + public DumpClassModel setMatchedClassLoaders(Collection matchedClassLoaders) { + this.matchedClassLoaders = matchedClassLoaders; + return this; + } + } diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/GetStaticModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/GetStaticModel.java index 4c61f07c6..0c013cdfc 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/model/GetStaticModel.java +++ b/core/src/main/java/com/taobao/arthas/core/command/model/GetStaticModel.java @@ -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 matchedClasses; private ObjectVO field; private int expand; + private Collection 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 getMatchedClassLoaders() { + return matchedClassLoaders; + } + + public GetStaticModel setMatchedClassLoaders(Collection matchedClassLoaders) { + this.matchedClassLoaders = matchedClassLoaders; + return this; + } + @Override public String getType() { return "getstatic"; diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/JadModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/JadModel.java index e108a9a29..19a8691ba 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/model/JadModel.java +++ b/core/src/main/java/com/taobao/arthas/core/command/model/JadModel.java @@ -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 matchedClassLoaders; + private String classLoaderClass; //match multiple classes private Collection matchedClasses; @@ -52,4 +55,22 @@ public class JadModel extends ResultModel { public void setMatchedClasses(Collection matchedClasses) { this.matchedClasses = matchedClasses; } + + public String getClassLoaderClass() { + return classLoaderClass; + } + + public JadModel setClassLoaderClass(String classLoaderClass) { + this.classLoaderClass = classLoaderClass; + return this; + } + + public Collection getMatchedClassLoaders() { + return matchedClassLoaders; + } + + public JadModel setMatchedClassLoaders(Collection matchedClassLoaders) { + this.matchedClassLoaders = matchedClassLoaders; + return this; + } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/MemoryCompilerModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/MemoryCompilerModel.java index 59d9b732c..720ab1236 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/model/MemoryCompilerModel.java +++ b/core/src/main/java/com/taobao/arthas/core/command/model/MemoryCompilerModel.java @@ -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 files; + private Collection 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 getMatchedClassLoaders() { + return matchedClassLoaders; + } + + public MemoryCompilerModel setMatchedClassLoaders(Collection matchedClassLoaders) { + this.matchedClassLoaders = matchedClassLoaders; + return this; + } + @Override public String getType() { return "mc"; diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/RedefineModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/RedefineModel.java index 0b6a17833..f7873850d 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/model/RedefineModel.java +++ b/core/src/main/java/com/taobao/arthas/core/command/model/RedefineModel.java @@ -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 redefinedClasses; + private Collection matchedClassLoaders; + private String classLoaderClass; public RedefineModel() { redefinedClasses = new ArrayList(); @@ -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 getMatchedClassLoaders() { + return matchedClassLoaders; + } + + public RedefineModel setMatchedClassLoaders(Collection matchedClassLoaders) { + this.matchedClassLoaders = matchedClassLoaders; + return this; + } + @Override public String getType() { return "redefine"; diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/DumpClassView.java b/core/src/main/java/com/taobao/arthas/core/command/view/DumpClassView.java index 273728c67..47deb980c 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/view/DumpClassView.java +++ b/core/src/main/java/com/taobao/arthas/core/command/view/DumpClassView.java @@ -23,6 +23,12 @@ public class DumpClassView extends ResultView { @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()); diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/GetStaticView.java b/core/src/main/java/com/taobao/arthas/core/command/view/GetStaticView.java index b7f81e913..867f4259e 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/view/GetStaticView.java +++ b/core/src/main/java/com/taobao/arthas/core/command/view/GetStaticView.java @@ -16,6 +16,12 @@ public class GetStaticView extends ResultView { @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(); diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/JadView.java b/core/src/main/java/com/taobao/arthas/core/command/view/JadView.java index e80041bfd..4bcdce113 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/view/JadView.java +++ b/core/src/main/java/com/taobao/arthas/core/command/view/JadView.java @@ -19,6 +19,12 @@ public class JadView extends ResultView { @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()); diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/MemoryCompilerView.java b/core/src/main/java/com/taobao/arthas/core/command/view/MemoryCompilerView.java index e0f69a6c9..807155408 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/view/MemoryCompilerView.java +++ b/core/src/main/java/com/taobao/arthas/core/command/view/MemoryCompilerView.java @@ -9,6 +9,12 @@ import com.taobao.arthas.core.shell.command.CommandProcess; public class MemoryCompilerView extends ResultView { @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'); diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/RedefineView.java b/core/src/main/java/com/taobao/arthas/core/command/view/RedefineView.java index e364332aa..3096b9ab8 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/view/RedefineView.java +++ b/core/src/main/java/com/taobao/arthas/core/command/view/RedefineView.java @@ -10,6 +10,12 @@ public class RedefineView extends ResultView { @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"); diff --git a/site/src/site/sphinx/dump.md b/site/src/site/sphinx/dump.md index c02a6b395..ed614d19c 100644 --- a/site/src/site/sphinx/dump.md +++ b/site/src/site/sphinx/dump.md @@ -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 ` + +```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$AppClassLoader,katacoda目前环境是java8。 + +`--classLoaderClass` 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而`-c `是动态变化的。 diff --git a/site/src/site/sphinx/en/dump.md b/site/src/site/sphinx/en/dump.md index f582fc2aa..a4b92465f 100644 --- a/site/src/site/sphinx/en/dump.md +++ b/site/src/site/sphinx/en/dump.md @@ -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 `. + +```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 ` is dynamic. diff --git a/site/src/site/sphinx/en/getstatic.md b/site/src/site/sphinx/en/getstatic.md index dfd971b37..1e3b77710 100644 --- a/site/src/site/sphinx/en/getstatic.md +++ b/site/src/site/sphinx/en/getstatic.md @@ -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 `. + +if you use`-c`, you have to manually type hashcode by `-c `. + +```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 ` 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. diff --git a/site/src/site/sphinx/en/jad.md b/site/src/site/sphinx/en/jad.md index da7ef5909..4c7347bec 100644 --- a/site/src/site/sphinx/en/jad.md +++ b/site/src/site/sphinx/en/jad.md @@ -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 ` is dynamic. diff --git a/site/src/site/sphinx/en/logger.md b/site/src/site/sphinx/en/logger.md index 0432fef9c..b2d9d1eeb 100644 --- a/site/src/site/sphinx/en/logger.md +++ b/site/src/site/sphinx/en/logger.md @@ -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 default,logger 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 hashcode,then specify classloader when updating logger level: ```bash [arthas@2062]$ logger -c 2a139a55 --name ROOT --level debug diff --git a/site/src/site/sphinx/en/mc.md b/site/src/site/sphinx/en/mc.md index cc618ef70..455b655f3 100644 --- a/site/src/site/sphinx/en/mc.md +++ b/site/src/site/sphinx/en/mc.md @@ -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 diff --git a/site/src/site/sphinx/en/redefine.md b/site/src/site/sphinx/en/redefine.md index 580f8cec1..e1a36d48a 100644 --- a/site/src/site/sphinx/en/redefine.md +++ b/site/src/site/sphinx/en/redefine.md @@ -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 diff --git a/site/src/site/sphinx/getstatic.md b/site/src/site/sphinx/getstatic.md index b36aee3ab..3def137c4 100644 --- a/site/src/site/sphinx/getstatic.md +++ b/site/src/site/sphinx/getstatic.md @@ -30,6 +30,25 @@ field: random ] ``` +* 指定classLoader + +注意hashcode是变化的,需要先查看当前的ClassLoader信息,使用`sc -d `提取对应ClassLoader的hashcode。 + +如果你使用`-c`,你需要手动输入hashcode:`-c ` + +```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$AppClassLoader,katacoda目前环境是java8。 + +`--classLoaderClass` 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而`-c `是动态变化的。 + + 如果该静态属性是一个复杂对象,还可以支持在该属性上通过ognl表示进行遍历,过滤,访问对象的内部属性等操作。 * OGNL特殊用法请参考:[https://github.com/alibaba/arthas/issues/71](https://github.com/alibaba/arthas/issues/71) diff --git a/site/src/site/sphinx/jad.md b/site/src/site/sphinx/jad.md index 2a47c52bd..5fea91ed9 100644 --- a/site/src/site/sphinx/jad.md +++ b/site/src/site/sphinx/jad.md @@ -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 `是动态变化的。 diff --git a/site/src/site/sphinx/mc.md b/site/src/site/sphinx/mc.md index 76e69ed7b..a50c5b9a0 100644 --- a/site/src/site/sphinx/mc.md +++ b/site/src/site/sphinx/mc.md @@ -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 diff --git a/site/src/site/sphinx/redefine.md b/site/src/site/sphinx/redefine.md index 97d3d5b9a..872d74cad 100644 --- a/site/src/site/sphinx/redefine.md +++ b/site/src/site/sphinx/redefine.md @@ -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 命令使用 diff --git a/tutorials/katacoda/arthas-advanced-cn/case-jad-mc-redefine.md b/tutorials/katacoda/arthas-advanced-cn/case-jad-mc-redefine.md index 6cb8d7fc5..74650eb6d 100644 --- a/tutorials/katacoda/arthas-advanced-cn/case-jad-mc-redefine.md +++ b/tutorials/katacoda/arthas-advanced-cn/case-jad-mc-redefine.md @@ -47,21 +47,25 @@ $ sc -d *UserController | grep classLoaderHash 请记下你的classLoaderHash,后面需要使用它。在这里,它是 `1be6f5c3`。 -注意:请使用你的classLoaderHash值覆盖 `` ,然后手动执行这些命令: - ### mc -保存好`/tmp/UserController.java`之后,使用`mc`(Memory Compiler)命令来编译,并且通过`-c`参数指定ClassLoader: +保存好`/tmp/UserController.java`之后,使用`mc`(Memory Compiler)命令来编译,并且通过`-c`或者`--classLoaderClass`参数指定ClassLoader: -`mc -c /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 /tmp/UserController.java -d /tmp`,使用`-c`参数指定ClassLoaderHash: + +```bash +$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp +``` + ### redefine 再使用`redefine`命令重新加载新编译好的`UserController.class`: diff --git a/tutorials/katacoda/arthas-advanced-en/case-jad-mc-redefine.md b/tutorials/katacoda/arthas-advanced-en/case-jad-mc-redefine.md index 320395eb4..5de8a5036 100644 --- a/tutorials/katacoda/arthas-advanced-en/case-jad-mc-redefine.md +++ b/tutorials/katacoda/arthas-advanced-en/case-jad-mc-redefine.md @@ -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 `` 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 /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 /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: diff --git a/tutorials/katacoda/case-jad-mc-redefine-cn/case-jad-mc-redefine.md b/tutorials/katacoda/case-jad-mc-redefine-cn/case-jad-mc-redefine.md index 72ab774fc..da6036af9 100644 --- a/tutorials/katacoda/case-jad-mc-redefine-cn/case-jad-mc-redefine.md +++ b/tutorials/katacoda/case-jad-mc-redefine-cn/case-jad-mc-redefine.md @@ -45,23 +45,33 @@ $ sc -d *UserController | grep classLoaderHash 可以发现是 spring boot `LaunchedURLClassLoader@1be6f5c3` 加载的。 -请记下你的classLoaderHash,后面需要使用它。在这里,它是 `1be6f5c3`。 +注意hashcode是变化的,需要先查看当前的ClassLoader信息,提取对应ClassLoader的hashcode。 -注意:请使用你的classLoaderHash值覆盖 `` ,然后手动执行下面所有所述命令: +如果你使用`-c`,你需要手动输入hashcode:`-c ` + +对于只有唯一实例的ClassLoader可以通过`--classLoaderClass`指定class name,使用起来更加方便. + +`--classLoaderClass` 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而`-c `是动态变化的。 ### mc -保存好`/tmp/UserController.java`之后,使用`mc`(Memory Compiler)命令来编译,并且通过`-c`参数指定ClassLoader: +保存好`/tmp/UserController.java`之后,使用`mc`(Memory Compiler)命令来编译,并且通过`--classLoaderClass`参数指定ClassLoader: -`mc -c /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 /tmp/UserController.java -d /tmp`,使用`-c`参数指定ClassLoaderHash: + +```bash +$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp +``` + ### redefine 再使用`redefine`命令重新加载新编译好的`UserController.class`: diff --git a/tutorials/katacoda/case-jad-mc-redefine-en/case-jad-mc-redefine.md b/tutorials/katacoda/case-jad-mc-redefine-en/case-jad-mc-redefine.md index 33468fbf1..80e93c96f 100644 --- a/tutorials/katacoda/case-jad-mc-redefine-en/case-jad-mc-redefine.md +++ b/tutorials/katacoda/case-jad-mc-redefine-en/case-jad-mc-redefine.md @@ -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 `` 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 `. + +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 ` 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 /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 /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: diff --git a/tutorials/katacoda/command-dump-cn/dump.md b/tutorials/katacoda/command-dump-cn/dump.md index d74efdea7..4c02ffd49 100644 --- a/tutorials/katacoda/command-dump-cn/dump.md +++ b/tutorials/katacoda/command-dump-cn/dump.md @@ -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 ` + +```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$AppClassLoader,katacoda目前环境是java8。 + +`--classLoaderClass` 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而`-c `是动态变化的。 diff --git a/tutorials/katacoda/command-dump-en/dump.md b/tutorials/katacoda/command-dump-en/dump.md index 0a2dab323..e74e14d98 100644 --- a/tutorials/katacoda/command-dump-en/dump.md +++ b/tutorials/katacoda/command-dump-en/dump.md @@ -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 `. + +```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 ` is dynamic. diff --git a/tutorials/katacoda/command-getstatic-cn/getstatic.md b/tutorials/katacoda/command-getstatic-cn/getstatic.md index 0f2e052f0..6fa8b8ec6 100644 --- a/tutorials/katacoda/command-getstatic-cn/getstatic.md +++ b/tutorials/katacoda/command-getstatic-cn/getstatic.md @@ -28,6 +28,24 @@ field: random ] ``` +* 指定classLoader + +注意hashcode是变化的,需要先查看当前的ClassLoader信息,使用`sc -d `提取对应ClassLoader的hashcode。 + +如果你使用`-c`,你需要手动输入hashcode:`-c ` + +```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$AppClassLoader,katacoda目前环境是java8。 + +`--classLoaderClass` 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而`-c `是动态变化的。 + 如果该静态属性是一个复杂对象,还可以支持在该属性上通过ognl表示进行遍历,过滤,访问对象的内部属性等操作。 * OGNL特殊用法请参考:[https://github.com/alibaba/arthas/issues/71](https://github.com/alibaba/arthas/issues/71) diff --git a/tutorials/katacoda/command-getstatic-en/getstatic.md b/tutorials/katacoda/command-getstatic-en/getstatic.md index 29b1585cb..a271f7c16 100644 --- a/tutorials/katacoda/command-getstatic-en/getstatic.md +++ b/tutorials/katacoda/command-getstatic-en/getstatic.md @@ -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 `. + +if you use`-c`, you have to manually type hashcode by `-c `. + +```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 ` 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. diff --git a/tutorials/katacoda/command-jad-cn/jad.md b/tutorials/katacoda/command-jad-cn/jad.md index c17d22a55..98e0206ea 100644 --- a/tutorials/katacoda/command-jad-cn/jad.md +++ b/tutorials/katacoda/command-jad-cn/jad.md @@ -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 `是动态变化的。 diff --git a/tutorials/katacoda/command-jad-en/jad.md b/tutorials/katacoda/command-jad-en/jad.md index c8c4f2aba..12470aaf8 100644 --- a/tutorials/katacoda/command-jad-en/jad.md +++ b/tutorials/katacoda/command-jad-en/jad.md @@ -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 ` is dynamic. diff --git a/tutorials/katacoda/command-logger-cn/logger.md b/tutorials/katacoda/command-logger-cn/logger.md index 2ea5eb040..79ccc31e0 100644 --- a/tutorials/katacoda/command-logger-cn/logger.md +++ b/tutorials/katacoda/command-logger-cn/logger.md @@ -115,10 +115,10 @@ update logger level success. 可以先用 `sc -d yourClassName` 来查看具体的 classloader hashcode,然后在更新level时指定classloader: -`logger -c --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的信息 diff --git a/tutorials/katacoda/command-logger-en/logger.md b/tutorials/katacoda/command-logger-en/logger.md index c217b5f93..0985b36fd 100644 --- a/tutorials/katacoda/command-logger-en/logger.md +++ b/tutorials/katacoda/command-logger-en/logger.md @@ -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 default,logger 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 hashcode,then specify classloader when updating logger level: `logger --classLoaderClass sun.misc.Launcher$AppClassLoader --name ROOT --level debug`{{execute T2}} diff --git a/tutorials/katacoda/command-mc-redefine-cn/case-jad-mc-redefine.md b/tutorials/katacoda/command-mc-redefine-cn/case-jad-mc-redefine.md index 72ab774fc..da6036af9 100644 --- a/tutorials/katacoda/command-mc-redefine-cn/case-jad-mc-redefine.md +++ b/tutorials/katacoda/command-mc-redefine-cn/case-jad-mc-redefine.md @@ -45,23 +45,33 @@ $ sc -d *UserController | grep classLoaderHash 可以发现是 spring boot `LaunchedURLClassLoader@1be6f5c3` 加载的。 -请记下你的classLoaderHash,后面需要使用它。在这里,它是 `1be6f5c3`。 +注意hashcode是变化的,需要先查看当前的ClassLoader信息,提取对应ClassLoader的hashcode。 -注意:请使用你的classLoaderHash值覆盖 `` ,然后手动执行下面所有所述命令: +如果你使用`-c`,你需要手动输入hashcode:`-c ` + +对于只有唯一实例的ClassLoader可以通过`--classLoaderClass`指定class name,使用起来更加方便. + +`--classLoaderClass` 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而`-c `是动态变化的。 ### mc -保存好`/tmp/UserController.java`之后,使用`mc`(Memory Compiler)命令来编译,并且通过`-c`参数指定ClassLoader: +保存好`/tmp/UserController.java`之后,使用`mc`(Memory Compiler)命令来编译,并且通过`--classLoaderClass`参数指定ClassLoader: -`mc -c /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 /tmp/UserController.java -d /tmp`,使用`-c`参数指定ClassLoaderHash: + +```bash +$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp +``` + ### redefine 再使用`redefine`命令重新加载新编译好的`UserController.class`: diff --git a/tutorials/katacoda/command-mc-redefine-cn/mc.md b/tutorials/katacoda/command-mc-redefine-cn/mc.md index d1acc9b15..2408d8dca 100644 --- a/tutorials/katacoda/command-mc-redefine-cn/mc.md +++ b/tutorials/katacoda/command-mc-redefine-cn/mc.md @@ -2,6 +2,6 @@ > Memory Compiler/内存编译器,编译`.java`文件生成`.class`。 -可以通过`-c`参数指定classloader,`-d`参数指定输出目录 +可以通过`-c`/`--classLoaderClass`参数指定classloader,`-d`参数指定输出目录 编译生成`.class`文件之后,可以结合`redefine`命令实现热更新代码。 diff --git a/tutorials/katacoda/command-mc-redefine-cn/redefine.md b/tutorials/katacoda/command-mc-redefine-cn/redefine.md index 21dce3190..bb3688c0e 100644 --- a/tutorials/katacoda/command-mc-redefine-cn/redefine.md +++ b/tutorials/katacoda/command-mc-redefine-cn/redefine.md @@ -23,6 +23,7 @@ |参数名称|参数说明| |---:|:---| |[c:]|ClassLoader的hashcode| +|`[classLoaderClass:]`|指定执行表达式的 ClassLoader 的 class name| |[p:]|外部的`.class`文件的完整路径,支持多个| diff --git a/tutorials/katacoda/command-mc-redefine-en/case-jad-mc-redefine.md b/tutorials/katacoda/command-mc-redefine-en/case-jad-mc-redefine.md index 33468fbf1..80e93c96f 100644 --- a/tutorials/katacoda/command-mc-redefine-en/case-jad-mc-redefine.md +++ b/tutorials/katacoda/command-mc-redefine-en/case-jad-mc-redefine.md @@ -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 `` 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 `. + +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 ` 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 /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 /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: diff --git a/tutorials/katacoda/command-mc-redefine-en/mc.md b/tutorials/katacoda/command-mc-redefine-en/mc.md index 7204cdce3..6853f8998 100644 --- a/tutorials/katacoda/command-mc-redefine-en/mc.md +++ b/tutorials/katacoda/command-mc-redefine-en/mc.md @@ -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. diff --git a/tutorials/katacoda/command-mc-redefine-en/redefine.md b/tutorials/katacoda/command-mc-redefine-en/redefine.md index ec280a9e4..2d4fe8af9 100644 --- a/tutorials/katacoda/command-mc-redefine-en/redefine.md +++ b/tutorials/katacoda/command-mc-redefine-en/redefine.md @@ -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