本文次要钻研一下arthas的HttpTermServer

TermServer

com/taobao/arthas/core/shell/term/TermServer.java

public abstract class TermServer {    /**     * Create a term server for the Telnet protocol.     *     * @param configure     * @return the term server     */    public static TermServer createTelnetTermServer(Configure configure, ShellServerOptions options) {        int port = configure.getTelnetPort() != null ? configure.getTelnetPort() : ArthasConstants.TELNET_PORT;        return new TelnetTermServer(configure.getIp(), port, options.getConnectionTimeout());    }    /**     * Create a term server for the HTTP protocol, using an existing router.     *     * @return the term server     */    public static TermServer createHttpTermServer() {        // TODO        return null;    }    /**     * Set the term handler that will receive incoming client connections. When a remote terminal connects     * the {@code handler} will be called with the {@link Term} which can be used to interact with the remote     * terminal.     *     * @param handler the term handler     * @return this object     */    public abstract TermServer termHandler(Handler<Term> handler);    /**     * Bind the term server, the {@link #termHandler(Handler)} must be set before.     *     * @return this object     */    public TermServer listen() {        return listen(null);    }    /**     * Bind the term server, the {@link #termHandler(Handler)} must be set before.     *     * @param listenHandler the listen handler     * @return this object     */    public abstract TermServer listen(Handler<Future<TermServer>> listenHandler);    /**     * The actual port the server is listening on. This is useful if you bound the server specifying 0 as port number     * signifying an ephemeral port     *     * @return the actual port the server is listening on.     */    public abstract int actualPort();    /**     * Close the server. This will close any currently open connections. The close may not complete until after this     * method has returned.     */    public abstract void close();    /**     * Like {@link #close} but supplying a handler that will be notified when close is complete.     *     * @param completionHandler the handler to be notified when the term server is closed     */    public abstract void close(Handler<Future<Void>> completionHandler);}
TermServer是一个抽象类,它定义了termHandler、listen、actualPort、close形象办法

HttpTermServer

com/taobao/arthas/core/shell/term/impl/HttpTermServer.java

public class HttpTermServer extends TermServer {    private static final Logger logger = LoggerFactory.getLogger(HttpTermServer.class);    private Handler<Term> termHandler;    private NettyWebsocketTtyBootstrap bootstrap;    private String hostIp;    private int port;    private long connectionTimeout;    private EventExecutorGroup workerGroup;    private HttpSessionManager httpSessionManager;    public HttpTermServer(String hostIp, int port, long connectionTimeout, EventExecutorGroup workerGroup, HttpSessionManager httpSessionManager) {        this.hostIp = hostIp;        this.port = port;        this.connectionTimeout = connectionTimeout;        this.workerGroup = workerGroup;        this.httpSessionManager = httpSessionManager;    }    @Override    public TermServer termHandler(Handler<Term> handler) {        this.termHandler = handler;        return this;    }    @Override    public TermServer listen(Handler<Future<TermServer>> listenHandler) {        // TODO: charset and inputrc from options        bootstrap = new NettyWebsocketTtyBootstrap(workerGroup, httpSessionManager).setHost(hostIp).setPort(port);        try {            bootstrap.start(new Consumer<TtyConnection>() {                @Override                public void accept(final TtyConnection conn) {                    termHandler.handle(new TermImpl(Helper.loadKeymap(), conn));                }            }).get(connectionTimeout, TimeUnit.MILLISECONDS);            listenHandler.handle(Future.<TermServer>succeededFuture());        } catch (Throwable t) {            logger.error("Error listening to port " + port, t);            listenHandler.handle(Future.<TermServer>failedFuture(t));        }        return this;    }    @Override    public int actualPort() {        return bootstrap.getPort();    }    @Override    public void close() {        close(null);    }    @Override    public void close(Handler<Future<Void>> completionHandler) {        if (bootstrap != null) {            bootstrap.stop();            if (completionHandler != null) {                completionHandler.handle(Future.<Void>succeededFuture());            }        } else {            if (completionHandler != null) {                completionHandler.handle(Future.<Void>failedFuture("telnet term server not started"));            }        }    }}
HttpTermServer继承了TermServer,其listen办法创立NettyWebsocketTtyBootstrap,而后执行其start办法,其accept办法执行的是termHandler.handle(new TermImpl(Helper.loadKeymap(), conn)),最初执行listenHandler.handle(Future.<TermServer>succeededFuture());其close办法执行的是bootstrap.stop()

Handler

com/taobao/arthas/core/shell/handlers/Handler.java

public interface Handler<E> {    /**     * Something has happened, so handle it.     *     * @param event the event to handle     */    void handle(E event);}
Handler定义了handle办法

TermServerTermHandler

com/taobao/arthas/core/shell/handlers/server/TermServerTermHandler.java

public class TermServerTermHandler implements Handler<Term> {    private ShellServerImpl shellServer;    public TermServerTermHandler(ShellServerImpl shellServer) {        this.shellServer = shellServer;    }    @Override    public void handle(Term term) {        shellServer.handleTerm(term);    }}
TermServerTermHandler实现了Handler接口,其handle办法执行的是shellServer.handleTerm(term)

ShellServerImpl

com/taobao/arthas/core/shell/impl/ShellServerImpl.java

    public void handleTerm(Term term) {        synchronized (this) {            // That might happen with multiple ser            if (closed) {                term.close();                return;            }        }        ShellImpl session = createShell(term);        tryUpdateWelcomeMessage();        session.setWelcome(welcomeMessage);        session.closedFuture.setHandler(new SessionClosedHandler(this, session));        session.init();        sessions.put(session.id, session); // Put after init so the close handler on the connection is set        session.readline(); // Now readline    }
ShellServerImpl的handleTerm办法创立ShellImpl,而后执行init,最初执行readline

readline

com/taobao/arthas/core/shell/impl/ShellImpl.java

    public void readline() {        term.readline(prompt, new ShellLineHandler(this),                new CommandManagerCompletionHandler(commandManager));    }
ShellImpl的readline委托给了Term,传入ShellLineHandler

ShellLineHandler

com/taobao/arthas/core/shell/handlers/shell/ShellLineHandler.java

    public void handle(String line) {        if (line == null) {            // EOF            handleExit();            return;        }        List<CliToken> tokens = CliTokens.tokenize(line);        CliToken first = TokenUtils.findFirstTextToken(tokens);        if (first == null) {            // For now do like this            shell.readline();            return;        }        String name = first.value();        if (name.equals("exit") || name.equals("logout") || name.equals("q") || name.equals("quit")) {            handleExit();            return;        } else if (name.equals("jobs")) {            handleJobs();            return;        } else if (name.equals("fg")) {            handleForeground(tokens);            return;        } else if (name.equals("bg")) {            handleBackground(tokens);            return;        } else if (name.equals("kill")) {            handleKill(tokens);            return;        }        Job job = createJob(tokens);        if (job != null) {            job.run();        }    }
ShellLineHandler的handle办法才是真正解决命令的中央,它反对了exit、logout、q、quit、jobs、fg、bg、kill命令

小结

HttpTermServer继承了TermServer,其listen办法创立NettyWebsocketTtyBootstrap,而后执行其start办法,其accept办法执行的是termHandler.handle(new TermImpl(Helper.loadKeymap(), conn)),最初执行listenHandler.handle(Future.<TermServer>succeededFuture());其close办法执行的是bootstrap.stop()。