【Arthas】Arthas Command处理流程

x33g5p2x  于2022-04-19 转载在 其他  
字(11.3k)|赞(0)|评价(0)|浏览(308)

1.概述

转载:Arthas Command处理流程

2.开篇

这篇文章主要是为了分析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

3.任务创建和执行

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的任务并执行

4.任务创建流程

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进行包装。

5.任务执行流程

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方法完成对应命令的执行

相关文章