Arthas Command处理流程
2021-05-04 本文已影响0人
晴天哥_王志
系列
- Arthas入门篇
- Arthas功能介绍
- Arthas 启动过程分析
- Arthas使用Idea调试
- Arthas Command处理流程
- Arthas类查找和反编译原理
- Arthas内存动态编译原理
- Arthas动态重新加载类
- Arthas导出加载类
开篇
- 这篇文章主要是为了分析Arthas的命令的执行过程,整体过程包括任务的创建和任务的执行。
- arthas的命令都是实现统一的接口,对外通过process方法进行调用。
public abstract class AnnotatedCommand {
// 不同的命令又不同的process实现
public abstract void process(CommandProcess process);
}
├── AbstractTraceAdviceListener.java
├── DashboardCommand.java
├── DashboardInterruptHandler.java
├── EnhancerCommand.java
├── GroovyAdviceListener.java
├── GroovyScriptCommand.java
├── HeapDumpCommand.java
├── JvmCommand.java
├── MBeanCommand.java
├── MonitorAdviceListener.java
├── MonitorCommand.java
├── MonitorData.java
├── PathTraceAdviceListener.java
├── PerfCounterCommand.java
├── ProfilerCommand.java
├── StackAdviceListener.java
├── StackCommand.java
├── ThreadCommand.java
├── ThreadSampler.java
├── TimeFragment.java
├── TimeTunnelAdviceListener.java
├── TimeTunnelCommand.java
├── TimeTunnelTable.java
├── TraceAdviceListener.java
├── TraceCommand.java
├── TraceEntity.java
├── WatchAdviceListener.java
└── WatchCommand.java
任务创建和执行
public class ShellLineHandler implements Handler<String> {
private ShellImpl shell;
private Term term;
@Override
public void handle(String line) {
List<CliToken> tokens = CliTokens.tokenize(line);
// 解析参数生成tokens,根据tokens来创建Job
Job job = createJob(tokens);
if (job != null) {
// 执行任务
job.run();
}
}
// 根据请求参数创建任务
private Job createJob(List<CliToken> tokens) {
Job job;
try {
job = shell.createJob(tokens);
} catch (Exception e) {
// 省略无关代码
}
return job;
}
}
- createJob根据传入参数创建Job对象
- 通过job.run()来执行Job任务
- 如sc *命令,那么根据sc关键字创建SearchClassCommand的任务并执行
任务创建流程
public class ShellImpl implements Shell {
private JobControllerImpl jobController;
public synchronized Job createJob(List<CliToken> args) {
Job job = jobController.createJob(commandManager, args, session, new ShellJobHandler(this), term, null);
return job;
}
}
public class GlobalJobControllerImpl extends JobControllerImpl {
public Job createJob(InternalCommandManager commandManager, List<CliToken> tokens, Session session, JobListener jobHandler, Term term, ResultDistributor resultDistributor) {
final Job job = super.createJob(commandManager, tokens, session, jobHandler, term, resultDistributor);
JobTimeoutTask jobTimeoutTask = new JobTimeoutTask(job);
long jobTimeoutInSecond = getJobTimeoutInSecond();
Date timeoutDate = new Date(System.currentTimeMillis() + (jobTimeoutInSecond * 1000));
ArthasBootstrap.getInstance().getScheduledExecutorService().schedule(jobTimeoutTask, jobTimeoutInSecond, TimeUnit.SECONDS);
jobTimeoutTaskMap.put(job.id(), jobTimeoutTask);
job.setTimeoutDate(timeoutDate);
return job;
}
}
public class JobControllerImpl implements JobController {
public Job createJob(InternalCommandManager commandManager, List<CliToken> tokens, Session session, JobListener jobHandler, Term term, ResultDistributor resultDistributor) {
checkPermission(session, tokens.get(0));
int jobId = idGenerator.incrementAndGet();
StringBuilder line = new StringBuilder();
for (CliToken arg : tokens) {
line.append(arg.raw());
}
boolean runInBackground = runInBackground(tokens);
// 根据tokens创建Process对象
Process process = createProcess(session, tokens, commandManager, jobId, term, resultDistributor);
process.setJobId(jobId);
// 创建JobImpl包含Process对象
JobImpl job = new JobImpl(jobId, this, process, line.toString(), runInBackground, session, jobHandler);
jobs.put(jobId, job);
return job;
}
}
- createProcess创建tokens对应的Process对象
- JobImpl将创建的Process对象进行封装,Job的执行会调用Process的方法
public class JobControllerImpl implements JobController {
private Process createProcess(Session session, List<CliToken> line, InternalCommandManager commandManager, int jobId, Term term, ResultDistributor resultDistributor) {
try {
ListIterator<CliToken> tokens = line.listIterator();
while (tokens.hasNext()) {
CliToken token = tokens.next();
if (token.isText()) {
// check before create process
checkPermission(session, token);
// 1、获取命令对应的处理函数对象Command
Command command = commandManager.getCommand(token.value());
if (command != null) {
// 2、创建Process对象
return createCommandProcess(command, tokens, jobId, term, resultDistributor);
} else {
throw new IllegalArgumentException(token.value() + ": command not found");
}
}
}
throw new IllegalArgumentException();
} catch (Exception e) {
}
}
private Process createCommandProcess(Command command, ListIterator<CliToken> tokens, int jobId, Term term, ResultDistributor resultDistributor) throws IOException {
// 省略相关代码
ProcessImpl process = new ProcessImpl(command, remaining, command.processHandler(), ProcessOutput, resultDistributor);
process.setTty(term);
return process;
}
}
public class InternalCommandManager {
private final List<CommandResolver> resolvers;
public InternalCommandManager(List<CommandResolver> resolvers) {
this.resolvers = resolvers;
}
public Command getCommand(String commandName) {
Command command = null;
for (CommandResolver resolver : resolvers) {
// 内建命令在ShellLineHandler里提前处理了,所以这里不需要再查找内建命令
if (resolver instanceof BuiltinCommandPack) {
command = getCommand(resolver, commandName);
if (command != null) {
break;
}
}
}
return command;
}
private static Command getCommand(CommandResolver commandResolver, String name) {
List<Command> commands = commandResolver.commands();
for (Command command : commands) {
if (name.equals(command.name())) {
return command;
}
}
}
}
- 根据命令的tokens去查询commands获取对应的command创建Process对象。
- 查询返回的command是AnnotatedCommandImpl对象。
public class BuiltinCommandPack implements CommandResolver {
private static List<Command> commands = new ArrayList<Command>();
static {
initCommands();
}
@Override
public List<Command> commands() {
return commands;
}
private static void initCommands() {
commands.add(Command.create(HelpCommand.class));
commands.add(Command.create(AuthCommand.class));
commands.add(Command.create(KeymapCommand.class));
commands.add(Command.create(SearchClassCommand.class));
commands.add(Command.create(SearchMethodCommand.class));
commands.add(Command.create(ClassLoaderCommand.class));
commands.add(Command.create(JadCommand.class));
commands.add(Command.create(GetStaticCommand.class));
commands.add(Command.create(MonitorCommand.class));
commands.add(Command.create(StackCommand.class));
commands.add(Command.create(ThreadCommand.class));
commands.add(Command.create(TraceCommand.class));
commands.add(Command.create(WatchCommand.class));
commands.add(Command.create(TimeTunnelCommand.class));
commands.add(Command.create(JvmCommand.class));
commands.add(Command.create(PerfCounterCommand.class));
// commands.add(Command.create(GroovyScriptCommand.class));
commands.add(Command.create(OgnlCommand.class));
commands.add(Command.create(MemoryCompilerCommand.class));
commands.add(Command.create(RedefineCommand.class));
commands.add(Command.create(RetransformCommand.class));
commands.add(Command.create(DashboardCommand.class));
commands.add(Command.create(DumpClassCommand.class));
commands.add(Command.create(HeapDumpCommand.class));
commands.add(Command.create(JulyCommand.class));
commands.add(Command.create(ThanksCommand.class));
commands.add(Command.create(OptionsCommand.class));
commands.add(Command.create(ClsCommand.class));
commands.add(Command.create(ResetCommand.class));
commands.add(Command.create(VersionCommand.class));
commands.add(Command.create(SessionCommand.class));
commands.add(Command.create(SystemPropertyCommand.class));
commands.add(Command.create(SystemEnvCommand.class));
commands.add(Command.create(VMOptionCommand.class));
commands.add(Command.create(LoggerCommand.class));
commands.add(Command.create(HistoryCommand.class));
commands.add(Command.create(CatCommand.class));
commands.add(Command.create(Base64Command.class));
commands.add(Command.create(EchoCommand.class));
commands.add(Command.create(PwdCommand.class));
commands.add(Command.create(MBeanCommand.class));
commands.add(Command.create(GrepCommand.class));
commands.add(Command.create(TeeCommand.class));
commands.add(Command.create(ProfilerCommand.class));
commands.add(Command.create(ShutdownCommand.class));
commands.add(Command.create(StopCommand.class));
}
}
public abstract class Command {
public static Command create(final Class<? extends AnnotatedCommand> clazz) {
return new AnnotatedCommandImpl(clazz);
}
}
public class AnnotatedCommandImpl extends Command {
private CLI cli;
private Class<? extends AnnotatedCommand> clazz;
private Handler<CommandProcess> processHandler = new ProcessHandler();
public AnnotatedCommandImpl(Class<? extends AnnotatedCommand> clazz) {
this.clazz = clazz;
cli = CLIConfigurator.define(clazz, true);
cli.addOption(new Option().setArgName("help").setFlag(true).setShortName("h").setLongName("help")
.setDescription("this help").setHelp(true));
}
public Handler<CommandProcess> processHandler() {
return processHandler;
}
private void process(CommandProcess process) {
AnnotatedCommand instance;
try {
instance = clazz.newInstance();
} catch (Exception e) {
process.end();
return;
}
CLIConfigurator.inject(process.commandLine(), instance);
instance.process(process);
UserStatUtil.arthasUsageSuccess(name(), process.args());
}
private class ProcessHandler implements Handler<CommandProcess> {
@Override
public void handle(CommandProcess process) {
process(process);
}
}
}
- BuiltinCommandPack包含所有arthas支持的命令
- 所有arthas支持的命令都用AnnotatedCommandImpl进行包装。
任务执行流程
public class JobImpl implements Job {
// 保存Process对象
final Process process;
public Job run(boolean foreground) {
actualStatus = ExecStatus.RUNNING;
if (statusUpdateHandler != null) {
statusUpdateHandler.handle(ExecStatus.RUNNING);
}
// 执行Process的run方法
process.setSession(this.session);
process.run(foreground);
if (this.status() == ExecStatus.RUNNING) {
if (foreground) {
jobHandler.onForeground(this);
} else {
jobHandler.onBackground(this);
}
}
return this;
}
}
- Job的执行是执行Process对象,执行Process的run方法
public class ProcessImpl implements Process {
public synchronized void run(boolean fg) {
// Make a local copy
final Tty tty = this.tty;
// 将Process封装成CommandProcessImpl对象
process = new CommandProcessImpl(this, tty);
// 省略代码
// 封装成CommandProcessTask对象
Runnable task = new CommandProcessTask(process);
// 通过线程池执行任务
ArthasBootstrap.getInstance().execute(task);
}
private class CommandProcessImpl implements CommandProcess {
private final Process process;
private final Tty tty;
private List<String> args2;
private CommandLine commandLine;
private AtomicInteger times = new AtomicInteger();
private AdviceListener listener = null;
private ClassFileTransformer transformer;
public CommandProcessImpl(Process process, Tty tty) {
this.process = process;
this.tty = tty;
}
}
}
- ProcessImpl封装成CommandProcessImpl对象
- CommandProcessImpl封装成CommandProcessTask对象
- CommandProcessTask的run调用ProcessHandler的handle方法执行ProcessImpl
public class ProcessImpl implements Process {
private Command commandContext;
// handler是ProcessHandler对象
private Handler<CommandProcess> handler;
private class CommandProcessTask implements Runnable {
private CommandProcess process;
public CommandProcessTask(CommandProcess process) {
this.process = process;
}
@Override
public void run() {
try {
handler.handle(process);
} catch (Throwable t) {
logger.error("Error during processing the command:", t);
process.end(1, "Error during processing the command: " + t.getClass().getName() + ", message:" + t.getMessage()
+ ", please check $HOME/logs/arthas/arthas.log for more details." );
}
}
}
}
- 执行ProcessHandler的handle方法
public class AnnotatedCommandImpl extends Command {
private CLI cli;
private Class<? extends AnnotatedCommand> clazz;
private Handler<CommandProcess> processHandler = new ProcessHandler();
private class ProcessHandler implements Handler<CommandProcess> {
@Override
public void handle(CommandProcess process) {
process(process);
}
}
private void process(CommandProcess process) {
AnnotatedCommand instance;
try {
// 创建命令的实例对象
instance = clazz.newInstance();
} catch (Exception e) {
process.end();
return;
}
CLIConfigurator.inject(process.commandLine(), instance);
// 执行命令的process方法
instance.process(process);
UserStatUtil.arthasUsageSuccess(name(), process.args());
}
}
- 实例化命令的对象并执行对应的process方法完成对应命令的执行