是否有另一种方法来启动远程jvm?

时间:2017-10-09 08:19:35

标签: java java-9 jshell

我正在使用JDK9的JShell API。

目前,JShell API在内部自动启动远程JVM。我不想自动启动流程,而是将这两个流程分开。

注意:我知道我可以更改VM选项。但是我想知道VM是否可以在不同的机器上运行。

默认执行控件最终reaches this place in code

如果我指定启动,它会自动使用com.sun.jdi.CommandLineLaunch连接器,它根据定义实际启动java程序。 如果我指定no-launch,它会像我期望的那样使用com.sun.jdi.SocketListen,一旦启动服务器套接字,它就会自动starts a remote vm and connects to this socket。我认为这是出乎意料的。

我试过的其他事情,

Shell jshell = JShell.builder()
    .executionEngine("jdi:hostname(localhost),launch(false)")
    .build();
jshell.eval("1+2");

我希望这会失败或被卡住,直到一个单独的过程开始。

是否有另一种方法来指定连接器,或者不启动JVM? (我对' local'也不感兴趣)

一些简单的选项,例如能够指定com.sun.jdi.RawCommandLineLaunch作为接受自定义命令的连接器,或者能够使用套接字侦听连接器并等待其他进程连接。

感谢。

1 个答案:

答案 0 :(得分:2)

编辑:我发现了一个错误 - 这不应该工作,因为JDWP没有连接到新的VM。

是的,这可以通过快速黑客来完成。 my description的改编版本如下:

hack依赖于替换JShell启动的VM中的代理。它可以通过remoteAgent execution parameter注入。

CLASSPATH="<injectpath>" ./jshell --execution "jdi:hostname(localhost),launch(false),remoteAgent(jshellhack.DumpPort),timeout(10000)"

新的虚拟代理必须以某种方式给出它应该连接的端口号。如果你不介意丑陋的黑客,那就像把它写到文件一样简单。您还可以利用命名管道。不过,我不建议任何严肃的事情。

一个简单的代理人:

package jshellhack;

import java.nio.file.*;
import java.lang.*;

import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.WRITE;
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;

public class DumpPort {

    public static void main(String[] args) throws Exception {
        String str = args[0] + "\n";
        OpenOption[] opts = new OpenOption[] { CREATE, WRITE, TRUNCATE_EXISTING };
        Files.write(Paths.get("/tmp/jshellargs"), str.getBytes(), opts);
    }
}

计算机上的JShell是JDWP频道的监听端。要重用现有的远程代理,您必须将所选端口反向转发到远程端。然后,您必须以远程端口作为参数在远程端运行原始代理。

使用SSH,它可能如下所示:

ssh -R "8000:localhost:$(cat /tmp/jshellargs)" ssh.example.org java jdk.jshell.execution.RemoteExecutionControl 8000

more robust solution可能涉及克隆JdiDefaultExecutionControlJdiInitiator实施并使用远程连接功能扩展它们。