Есть ли альтернативный способ запуска удаленного JVM?

Я играю с JSK API JDK9.

В настоящее время JShell API автоматически запускает удаленную JVM изнутри. Вместо того, чтобы запускать процесс автоматически, я хочу разделить два процесса.

Примечание. Я понимаю, что могу изменить параметры виртуальной машины. Но я хочу посмотреть, можно ли запустить виртуальную машину на другом компьютере.

Элемент управления по умолчанию в конечном итоге достигает этого места в коде.

Если я укажу запуск, он автоматически использует 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 в качестве соединителя, который принимает пользовательскую команду или может использовать соединитель прослушивания сокета и ожидать подключения другого процесса.

Благодарю.

1 ответ

РЕДАКТИРОВАТЬ: Я нашел ошибку в этом - это не должно работать, потому что JDWP не подключен к новой виртуальной машине.


Да, это может быть достигнуто с быстрым взломом. Адаптированная версия моего описания выглядит следующим образом:

Взлом основан на замене агента в виртуальной машине, запущенной JShell. Это может быть введено через remoteAgent параметр выполнения.

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

Более надежное решение, вероятно, будет включать клонирование реализаций JdiDefaultExecutionControl и JdiInitiator и расширение их с возможностью удаленного подключения.

Другие вопросы по тегам