四、Arthas

四、Arthas

    1、安装/卸载

        (1)、Arthas支持在Linux/Unix/Mac等平台上一键安装,请复制以下内容,并粘贴到命令行中,敲回车执行即可。

curl -L https://arthas.aliyun.com/install.sh | sh

            上述命令会下载启动脚本文件as.sh到当前目录,你可以放在任何地方或将其加入到$PATH中。直接在shell下面执行./as.sh,就会进入交互界面。也可以执行./as.sh -h来获取更多参数信息。

Das

        (2)、卸载

            在Linux/Unix/Mac平台删除下面文件。

rm -rf ~/.arthas/

rm -rf ~/logs/arthas

    2、运行

        执行:java -jar arthas-boot.jar 运行Arthas,粘附到指定Java应用进程

    3、命令

        (1)、基础命令

            help——查看命令帮助信息

            cls——清空当前屏幕区域

            session——查看当前会话的信息

            reset——重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类

            version——输出当前目标 Java 进程所加载的 Arthas 版本号

            history——打印命令历史

            quit——退出当前 Arthas 客户端,其他 Arthas 客户端不受影响

            stop——关闭 Arthas 服务端,所有 Arthas 客户端全部退出

            keymap——Arthas快捷键列表及自定义快捷键

        (2)、常用命令

            命令列表:命令列表 | arthas

            ①、dashboard 查看仪表盘,按Q或Ctrl + C可以中断执行。

            ②、thread 获取该进程的所有线程

                thread 1 查看序号为1线程的内容

            ③、jad java.lang.Object 反编译Object类方便查看

    4、源码分析

        (1)、arthas-boot模块

            ①、输入命令:java -jar arthas-boot.jar 或 ./as.sh

            ②、运行arthas-boot.jar中com.taobao.arthas.boot.Bootstrap#main方法,或者运行as.sh文件

            ③、获取arthas版本信息

            ④、解析命令传入参数,将参数解析成CommandLine对象

            ⑤、设置镜像仓库,日志打印等

            ⑥、端口校验是否被占用

            ⑦、获取pid,校验目标端口的pid和attach pid是否一致

            ⑧、获取arthas home,启动arthas-core.jar

        (2)、arthas-core模块

            ①、运行arthas-boot.jar中com.taobao.arthas.core.Arthas#main

            ②、将透传的参数解析转换成CommandLine对象

            ③、获取VirtualMachine.list()列表,匹配目标进程pid

            ④、利用VirtualMachine.attach(),attach到目标进程

            ⑤、利用virtualMachine.loadAgent()方法加载agent的jar包arthas-agent.jar 

        (3)、arthas-agent模块(从这开始所有代码都是运行在目标JVM中)

            ①、运行arthas-agent.jar中com.taobao.arthas.agent334.AgentBootstrap#main

            ②、对传递的参数解析

            ③、通过反射执行com.taobao.arthas.core.server.ArthasBootstrap#getInstance(Instrumentation ins, String args)方法,初始化spy和arthas命令

            ④、将arthas-spy.jar添加到BootstrapClassLoader加载目录下,解决一些ClassLoader加载不到SpyAPI的问题,加载SpyAPI,通过字节码插入到业务代码的逻辑类在arthas-spy.jar包

            ⑤、初始化arthas运行的环境变量

        (4)、arthas-spy.jar包

            ①、SpyAPI当中的6个“at…”静态方法都调用了实例spyInstance中对应的方法。spyInstance的静态类型是抽象类AbstractSpy,抽象类AbstractSpy当中有六个抽象方法。当SpyAPI被加载时,它的静态语句会将spyInstance设置为类NopSpy的实例,其中这NopSpy继承自AbstractSpy并且实现的每个方法都是空操作。

            ②、AbstractSpy抽象类

public static abstract class AbstractSpy {
    // 进入
    public abstract void atEnter(Class<?> clazz, String methodInfo, Object target, Object[] args);
    // 退出
    public abstract void atExit(Class<?> clazz, String methodInfo, Object target, Object[] args, Object returnObject);
    // 异常退出
    public abstract void atExceptionExit(Class<?> clazz, String methodInfo, Object target, Object[] args, Throwable throwable);
    // 调用前
    public abstract void atBeforeInvoke(Class<?> clazz, String invokeInfo, Object target);
    // 调用后
    public abstract void atAfterInvoke(Class<?> clazz, String invokeInfo, Object target);
    // 异常调用
    public abstract void atInvokeException(Class<?> clazz, String invokeInfo, Object target, Throwable throwable);
}

            ③、Enhancer类

                对类进行通知增强,继承ClassFileTransformer,并实现transform方法

public class Enhancer implements ClassFileTransformer {
    // 通过静态代码块初始化SpyAPI
    static {
        SpyAPI.setSpy(spyImpl);
    }

    @Override
    public byte[] transform(final ClassLoader inClassLoader, String className, Class<?> classBeingRedefined,
            ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        try {
            // 检查classloader能否加载到 SpyAPI,如果不能,则放弃增强
            try {
                if (inClassLoader != null) {
                    inClassLoader.loadClass(SpyAPI.class.getName());
                }
            } catch (Throwable e) {
                logger.error("the classloader can not load SpyAPI, ignore it. classloader: {}, className: {}",
                        inClassLoader.getClass().getName(), className, e);
                return null;
            }
        }
        ...
        return null;
    }
}

参考文章:

        (1)、消失的堆栈:消失的堆栈

        (2)、JVM Attach机制:JVM Attach机制实现 - 你假笨

        (3)、Arthas原理一:Arthas原理系列(一):利用JVM的attach机制实现一个极简的watch命令

        (4)、Arthas原理二:Arthas原理系列(二):总体架构和项目入口

        (5)、Arthas原理三:Arthas原理系列(三):服务端启动流程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值