diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java index 5a895ec83..9aeff13ce 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java @@ -3,7 +3,10 @@ package com.taobao.arthas.core.command.klass100; import com.taobao.arthas.core.command.Constants; 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.StringUtils; import com.taobao.arthas.core.util.affect.RowAffect; +import com.taobao.arthas.core.view.ObjectView; import com.taobao.middleware.cli.annotations.Description; import com.taobao.middleware.cli.annotations.Name; import com.taobao.middleware.cli.annotations.Option; @@ -38,10 +41,12 @@ import java.util.TreeSet; @Description(Constants.EXAMPLE + " classloader\n" + " classloader -t\n" + + " classloader -l\n" + " classloader -c 327a647b\n" + " classloader -c 327a647b -r META-INF/MANIFEST.MF\n" + " classloader -a\n" + " classloader -a -c 327a647b\n" + + " classloader -c 659e0bfd --load com.test.Demo\n" + Constants.WIKI + Constants.WIKI_HOME + "classloader") public class ClassLoaderCommand extends AnnotatedCommand { private boolean isTree = false; @@ -51,6 +56,8 @@ public class ClassLoaderCommand extends AnnotatedCommand { private boolean includeReflectionClassLoader = true; private boolean listClassLoader = false; + private String loadClass = null; + @Option(shortName = "t", longName = "tree", flag = true) @Description("Display ClassLoader tree") public void setTree(boolean tree) { @@ -87,6 +94,12 @@ public class ClassLoaderCommand extends AnnotatedCommand { this.listClassLoader = listClassLoader; } + @Option(longName = "load") + @Description("Use ClassLoader to load class, won't work without -c specified") + public void setLoadClass(String className) { + this.loadClass = className; + } + @Override public void process(CommandProcess process) { Instrumentation inst = process.session().getInstrumentation(); @@ -94,6 +107,8 @@ public class ClassLoaderCommand extends AnnotatedCommand { processAllClasses(process, inst); } else if (hashCode != null && resource != null) { processResources(process, inst); + } else if (hashCode != null && this.loadClass != null) { + processLoadClass(process, inst); } else if (hashCode != null) { processClassloader(process, inst); } else if (listClassLoader || isTree){ @@ -169,8 +184,7 @@ public class ClassLoaderCommand extends AnnotatedCommand { private void processResources(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); int rowCount = 0; - Set allClassLoader = includeReflectionClassLoader ? getAllClassLoader(inst) : - getAllClassLoader(inst, new SunReflectionClassLoaderFilter()); + Set allClassLoader = getAllClassLoader(inst); for (ClassLoader cl : allClassLoader) { if (Integer.toHexString(cl.hashCode()).equals(hashCode)) { TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); @@ -192,6 +206,26 @@ public class ClassLoaderCommand extends AnnotatedCommand { process.end(); } + // Use ClassLoader to loadClass + private void processLoadClass(CommandProcess process, Instrumentation inst) { + Set allClassLoader = getAllClassLoader(inst); + for (ClassLoader cl : allClassLoader) { + if (Integer.toHexString(cl.hashCode()).equals(hashCode)) { + try { + Class clazz = cl.loadClass(this.loadClass); + process.write("load class success.\n"); + process.write(RenderUtil.render(ClassUtils.renderClassInfo(clazz), process.width()) + "\n"); + + } catch (Throwable e) { + e.printStackTrace(); + process.write("load class error.\n" + StringUtils.objectToString(new ObjectView(e, 1).draw())); + } + } + } + process.write("\n"); + process.end(); + } + private void processAllClasses(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); process.write(RenderUtil.render(renderClasses(hashCode, inst), process.width())); 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 93de3c431..4a4c37869 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.taobao.arthas.core.advisor.Enhancer; import com.taobao.arthas.core.command.Constants; 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.FileUtils; import com.taobao.arthas.core.util.LogUtil; import com.taobao.arthas.core.util.SearchUtils; @@ -125,7 +126,7 @@ public class JadCommand extends AnnotatedCommand { process.write(RenderUtil.render(new LabelElement("ClassLoader: ").style(Decoration.bold.fg(Color.red)), process.width())); process.write(RenderUtil.render(TypeRenderUtils.drawClassLoader(c), process.width()) + "\n"); process.write(RenderUtil.render(new LabelElement("Location: ").style(Decoration.bold.fg(Color.red)), process.width())); - process.write(RenderUtil.render(new LabelElement(SearchClassCommand.getCodeSource( + process.write(RenderUtil.render(new LabelElement(ClassUtils.getCodeSource( c.getProtectionDomain().getCodeSource())).style(Decoration.bold.fg(Color.blue)), process.width()) + "\n"); process.write(LangRenderUtil.render(source) + "\n"); process.write(com.taobao.arthas.core.util.Constants.EMPTY_STRING); diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java index 8261cade7..2b615e088 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java @@ -1,9 +1,7 @@ package com.taobao.arthas.core.command.klass100; -import static com.taobao.text.ui.Element.label; import java.lang.instrument.Instrumentation; -import java.security.CodeSource; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -12,18 +10,15 @@ import java.util.List; import com.taobao.arthas.core.command.Constants; 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.SearchUtils; import com.taobao.arthas.core.util.StringUtils; -import com.taobao.arthas.core.util.TypeRenderUtils; import com.taobao.arthas.core.util.affect.RowAffect; import com.taobao.middleware.cli.annotations.Argument; import com.taobao.middleware.cli.annotations.Description; import com.taobao.middleware.cli.annotations.Name; import com.taobao.middleware.cli.annotations.Option; import com.taobao.middleware.cli.annotations.Summary; -import com.taobao.text.Decoration; -import com.taobao.text.ui.Element; -import com.taobao.text.ui.TableElement; import com.taobao.text.util.RenderUtil; /** @@ -46,14 +41,6 @@ public class SearchClassCommand extends AnnotatedCommand { private boolean isRegEx = false; private Integer expand; - public static String getCodeSource(final CodeSource cs) { - if (null == cs || null == cs.getLocation() || null == cs.getLocation().getFile()) { - return com.taobao.arthas.core.util.Constants.EMPTY_STRING; - } - - return cs.getLocation().getFile(); - } - @Argument(argName = "class-pattern", index = 0) @Description("Class name pattern, use either '.' or '/' as separator") public void setClassPattern(String classPattern) { @@ -108,40 +95,10 @@ public class SearchClassCommand extends AnnotatedCommand { private void processClass(CommandProcess process, Class clazz) { if (isDetail) { - process.write(RenderUtil.render(renderClassInfo(clazz, isField), process.width()) + "\n"); + process.write(RenderUtil.render(ClassUtils.renderClassInfo(clazz, isField, expand), process.width()) + "\n"); } else { process.write(clazz.getName() + "\n"); } } - private Element renderClassInfo(Class clazz, boolean isPrintField) { - TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); - CodeSource cs = clazz.getProtectionDomain().getCodeSource(); - - table.row(label("class-info").style(Decoration.bold.bold()), label(StringUtils.classname(clazz))) - .row(label("code-source").style(Decoration.bold.bold()), label(getCodeSource(cs))) - .row(label("name").style(Decoration.bold.bold()), label(StringUtils.classname(clazz))) - .row(label("isInterface").style(Decoration.bold.bold()), label("" + clazz.isInterface())) - .row(label("isAnnotation").style(Decoration.bold.bold()), label("" + clazz.isAnnotation())) - .row(label("isEnum").style(Decoration.bold.bold()), label("" + clazz.isEnum())) - .row(label("isAnonymousClass").style(Decoration.bold.bold()), label("" + clazz.isAnonymousClass())) - .row(label("isArray").style(Decoration.bold.bold()), label("" + clazz.isArray())) - .row(label("isLocalClass").style(Decoration.bold.bold()), label("" + clazz.isLocalClass())) - .row(label("isMemberClass").style(Decoration.bold.bold()), label("" + clazz.isMemberClass())) - .row(label("isPrimitive").style(Decoration.bold.bold()), label("" + clazz.isPrimitive())) - .row(label("isSynthetic").style(Decoration.bold.bold()), label("" + clazz.isSynthetic())) - .row(label("simple-name").style(Decoration.bold.bold()), label(clazz.getSimpleName())) - .row(label("modifier").style(Decoration.bold.bold()), label(StringUtils.modifier(clazz.getModifiers(), ','))) - .row(label("annotation").style(Decoration.bold.bold()), label(TypeRenderUtils.drawAnnotation(clazz))) - .row(label("interfaces").style(Decoration.bold.bold()), label(TypeRenderUtils.drawInterface(clazz))) - .row(label("super-class").style(Decoration.bold.bold()), TypeRenderUtils.drawSuperClass(clazz)) - .row(label("class-loader").style(Decoration.bold.bold()), TypeRenderUtils.drawClassLoader(clazz)) - .row(label("classLoaderHash").style(Decoration.bold.bold()), label(StringUtils.classLoaderHash(clazz))); - - if (isPrintField) { - table.row(label("fields"), TypeRenderUtils.drawField(clazz, expand)); - } - return table; - } - } diff --git a/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java b/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java new file mode 100644 index 000000000..817bb8002 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java @@ -0,0 +1,60 @@ +package com.taobao.arthas.core.util; + +import static com.taobao.text.ui.Element.label; + +import java.security.CodeSource; + +import com.taobao.text.Decoration; +import com.taobao.text.ui.Element; +import com.taobao.text.ui.TableElement; + +/** + * + * @author hengyunabc 2018-10-18 + * + */ +public class ClassUtils { + + public static String getCodeSource(final CodeSource cs) { + if (null == cs || null == cs.getLocation() || null == cs.getLocation().getFile()) { + return com.taobao.arthas.core.util.Constants.EMPTY_STRING; + } + + return cs.getLocation().getFile(); + } + + public static Element renderClassInfo(Class clazz) { + return renderClassInfo(clazz, false, null); + } + + public static Element renderClassInfo(Class clazz, boolean isPrintField, Integer expand) { + TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); + CodeSource cs = clazz.getProtectionDomain().getCodeSource(); + + table.row(label("class-info").style(Decoration.bold.bold()), label(StringUtils.classname(clazz))) + .row(label("code-source").style(Decoration.bold.bold()), label(getCodeSource(cs))) + .row(label("name").style(Decoration.bold.bold()), label(StringUtils.classname(clazz))) + .row(label("isInterface").style(Decoration.bold.bold()), label("" + clazz.isInterface())) + .row(label("isAnnotation").style(Decoration.bold.bold()), label("" + clazz.isAnnotation())) + .row(label("isEnum").style(Decoration.bold.bold()), label("" + clazz.isEnum())) + .row(label("isAnonymousClass").style(Decoration.bold.bold()), label("" + clazz.isAnonymousClass())) + .row(label("isArray").style(Decoration.bold.bold()), label("" + clazz.isArray())) + .row(label("isLocalClass").style(Decoration.bold.bold()), label("" + clazz.isLocalClass())) + .row(label("isMemberClass").style(Decoration.bold.bold()), label("" + clazz.isMemberClass())) + .row(label("isPrimitive").style(Decoration.bold.bold()), label("" + clazz.isPrimitive())) + .row(label("isSynthetic").style(Decoration.bold.bold()), label("" + clazz.isSynthetic())) + .row(label("simple-name").style(Decoration.bold.bold()), label(clazz.getSimpleName())) + .row(label("modifier").style(Decoration.bold.bold()), label(StringUtils.modifier(clazz.getModifiers(), ','))) + .row(label("annotation").style(Decoration.bold.bold()), label(TypeRenderUtils.drawAnnotation(clazz))) + .row(label("interfaces").style(Decoration.bold.bold()), label(TypeRenderUtils.drawInterface(clazz))) + .row(label("super-class").style(Decoration.bold.bold()), TypeRenderUtils.drawSuperClass(clazz)) + .row(label("class-loader").style(Decoration.bold.bold()), TypeRenderUtils.drawClassLoader(clazz)) + .row(label("classLoaderHash").style(Decoration.bold.bold()), label(StringUtils.classLoaderHash(clazz))); + + if (isPrintField) { + table.row(label("fields"), TypeRenderUtils.drawField(clazz, expand)); + } + return table; + } + +}