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

我正在玩JDK9的JShell API。

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

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

默认执行控件最终在代码中到达此位置 。

如果我指定启动,它会自动使用com.sun.jdi.CommandLineLaunch连接器,它实际上是按定义启动java程序。 如果我指定no-launch,它会像我期望的那样使用com.sun.jdi.SocketListen ,一旦启动服务器套接字,它就会自动启动一个远程虚拟机并连接到这个套接字 。 我认为这是出乎意料的。

我试过的其他事情,

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

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

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

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

谢谢。

编辑:我发现了一个错误 – 这应该不起作用,因为JDWP没有附加到新VM。


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

黑客依赖于替换JShell启动的VM中的代理。 它可以通过remoteAgent 执行参数注入。

 CLASSPATH="" ./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 

更强大的解决方案可能涉及克隆JdiDefaultExecutionControl和JdiInitiator实现并使用远程连接function扩展它们。