版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/u010597819/article/details/88554000
启动arthas-bootstrap
- 启动,如果没有参数启动则自动列举当前系统的java进程列表,等待用户选择
- 选择要attach的进程,并进行attach
- 拼接启动arthas-core的命令行,包含agent参数指定为arthas-agent.jar
- 启动arthas-core.jar
- 如果仅仅是attach则退出
- 如果不是仅attach,则启动arthas-client,入口:com.taobao.arthas.client.TelnetConsole.Main
启动arthas-core
// "${JAVA_HOME}"/bin/java \
// ${opts} \
// -jar "${arthas_lib_dir}/arthas-core.jar" \
// -pid ${TARGET_PID} \
// -target-ip ${TARGET_IP} \
// -telnet-port ${TELNET_PORT} \
// -http-port ${HTTP_PORT} \
// -core "${arthas_lib_dir}/arthas-core.jar" \
// -agent "${arthas_lib_dir}/arthas-agent.jar"
例如:
java -jar ${HOME}/.arthas/lib/3.1.0/arthas/arthas-core.jar
-pid 7320
-target-ip 127.0.0.1
-telnet-port 3658
-http-port 8563
-core "${HOME}/.arthas/lib/3.1.0/arthas/arthas-core.jar"
-agent "${HOME}/.arthas/lib/3.1.0/arthas/arthas-agent.jar"
- core入口Arthas.main,创建Arthas
- attach代理agent,attachAgent
- 遍历当前系统的虚拟机列表VirtualMachine.list,获取参数中指定要attach的pid进程
- attach目标虚拟机:VirtualMachine.attach
- 判断两个jvm的jdk版本,如果不一致打印warn日志
- 为指定目标jvm进程加载agent代理
virtualMachine.loadAgent(configure.getArthasAgent(),
configure.getArthasCore() + ";" + configure.toString());
C:\Users\Gallant\.arthas\lib\3.1.0\arthas\arthas-agent.jar=C:\Users\Gallant\.arthas\lib\3.1.0\arthas\arthas-core.jar;;telnetPort=3658;httpPort=8563;ip=127.0.0.1;arthasAgent=C:\\Users\\Gallant\\.arthas\\lib\\3.1.0\\arthas\\arthas-agent.jar;sessionTimeout=1800;arthasCore=C:\\Users\\Gallant\\.arthas\\lib\\3.1.0\\arthas\\arthas-core.jar;javaPid=7320;
启动arthas-agent
- 在为目标进程attach代理后,jvm回调指定的agent-class类的agentmain方法(同样启动时回调的是premain-class类的premain方法),回调AgentBootstrap的main方法
- 加载spy的jar包至BootstrapClassLoader并获取agent jar的classloader
- 初始化spy间谍
- 加载AdviceWeaver类
- 获取AdviceWeaver类的methodOnBegin、methodOnReturnEnd、methodOnThrowingEnd、methodOnInvokeBeforeTracing、methodOnInvokeAfterTracing、methodOnInvokeThrowTracing、resetArthasClassLoader方法
- 与Spy绑定
- 绑定bind
- 将args参数反序列化为Configure对象
- 获取要监控的进程pid(javaPid)
- 获取ArthasBootstrap实例调用判断是否已经绑定,没有则绑定
- ArthasBootstrap绑定bind
arthas-core绑定
- ArthasBootstrap绑定bind
- 创建shellserver(ShellServerImpl)并绑定端口
- 创建内建命令包BuiltinCommandPack
- 将内建命令包与shellserver绑定,作为resolver注册至服务
- 根据配置的ip及端口注册服务:TelnetTermServer、HttpTermServer
- shellServer启动监听:listen
- 遍历注册的服务注册handler(termHandler=TermServerTermHandler)并启动监听即:TelnetTermServer、HttpTermServer
- 假定为telnet服务模式
- 根据ip端口创建netty服务NettyTelnetTtyBootstrap,启动入参为factory:提供accept实现为termHandler.accept,accept入参为new TermImpl
bootstrap.start(new Consumer<TtyConnection>() {
@Override
public void accept(final TtyConnection conn) {
termHandler.handle(new TermImpl(Helper.loadKeymap(), conn));
}
}).get(connectionTimeout, TimeUnit.MILLISECONDS);
- 启动服务start委派telnet:NettyTelnetBootstrap.start启动
- 创建事件handler:TelnetChannelHandler
- 绑定ip端口并添加监听
- 事件处理handler:TelnetChannelHandler,factory工厂get属性为:TelnetTtyConnection
- TelnetChannelHandler读取数据channelRead,调用当前连接实例读取数据:NettyTelnetConnection.receive
- 委派状态handle数据,当前为DATA状态,委派当前session(即当前Connection实例)读取数据append,超过缓存就flush数据,绑定的handle读取数据onData
- 当前绑定的handler为factory工厂get获取(TelnetTtyConnection),TelnetTtyConnection.onData
- decoder写入数据(BinaryDecoder.write),将数据读取至本地ByteBuffer并回调onChar.accept(ReadBuffer.accept)
- ReadBuffer调用readHandler读取数据(TtyEventDecoder.accept),readerHandler在Connection连接open打开时设置为eventDecoder(TtyEventDecoder)
- TtyEventDecoder接收数据accept,eventHandler、readHandler读取数据,eventHandler、readHandler在TermImpl构造方法内设置为echoHandler:DefaultTermStdinHandler,EventHandler
- EventHandler读取指令根据指定调用termImpl实现的方法
- 读取标准输入数据DefaultTermStdinHandler.accept,调用term打印到标准输出,并将指令放入ReadLine实例绑定的队列
- 将指令放入事件队列:EventQueue.append
- 客户端指令读取完成
- TelnetTtyConnection连接打开时会check校验Accept回调handler.accept,也就是匿名实现的Consumer.accept
- term句柄(TermServerTermHandler)handle客户端实现termImpl,即直接委派shellServer handle处理termImpl
- 根据Term创建session(ShellImpl)
- 为session设置欢迎页面
- 设置session的关闭handle
- 初始化session
- session读取命令行readline,委派term执行,term委派ReadLine实例执行
- 从队列EventQueue中读取指令并将指令封装为KeyEvent对象
- 交互实例Interaction处理事件handle
- 根据KeyEvent事件获取对应的方法处理,例如完成处理Complete
- 即调用CompletionHandler处理数据
- CompletionHandler处理数据accept
- 读取命令行
- 解析命令行为CliToken列表
- CommandManagerCompletionHandler处理CompletionAdaptor
- 委派commandManager处理complete
- 处理命令completeSingleCommand、completeCommands
- Completion处理命令,即CompletionAdaptor.complete,适配器委派Completion处理complete
- 将指标输出至标准输出
- Accept处理
- RequestHandler处理接收请求,委派给lineHandler处理:ShellLineHandler.handle
- 根据命令行创建Job任务并执行
- ShellImpl根据命令行创建Job
- JobController创建Job
- 创建Process并绑定对应的Command,commandManager根据命令行创建对应的Command
- JobImpl绑定Process
- 执行Job,为Process设置term与session并执行
- 将process封装为CommandProcessTask提交至线程池执行,委派CommandProcessImpl handle process
- 即Command的processHandler处理:new ProcessImpl(command, remaining, command.processHandler(), ProcessOutput);
- 例如:MonitorCommand,封装为AnnotatedCommandImpl,processHandle为:ProcessHandler
- ProcessHandler处理命令CommandProcess,委派AnnotatedCommandImpl处理process
- 根据命令class创建实例并处理CommandProcess,如:MonitorCommand.process
- MonitorCommand命令委派父类处理enhance,即对相应的class进行enhance增强,即将对应的监听织入(例如:MonitorAdviceListener),Enhancer.enhance
- NettyTelnetTtyBootstrap启动完成后TermServerListenHandler来handle启动事件,如果启动失败,关闭server
- 如果server启动成功,则为shellServer启动定时任务监听session是否关闭;回调监听handler返回成功状态
arthas-core之enhance增强
- 创建Enhance实例
- 将enhance添加至Instrumentation
- Instrumentation修改类定义retransform
- 回调自定义的Enhancer.transform进行增强
- 调用ASM API对指定类增强处理,自定义类修改实现AdviceWeaver
- ASM回调visitMethod方法对指定方法增强,向方法中织入字节码:通过Method.invoke方法回调增强动作:ON_BEFORE_METHOD、ON_RETURN_METHOD、ON_THROWS_METHOD、BEFORE_INVOKING_METHOD、AFTER_INVOKING_METHOD、THROW_INVOKING_METHOD