2017-10-09 4 views
2

Je joue avec l'API JShell du JDK9.Existe-t-il un autre moyen de lancer jvm à distance?

Actuellement, l'API JShell lance automatiquement la JVM distante en interne. Au lieu de démarrer le processus automatiquement, je veux séparer les deux processus.

Remarque: Je comprends que je peux modifier les options de la machine virtuelle. Mais je veux voir si la VM peut même être exécutée sur une machine différente.

Le contrôle d'exécution par défaut est éventuellement reaches this place in code.

Si je spécifie le lancement, il utilise automatiquement le connecteur com.sun.jdi.CommandLineLaunch, qui lance réellement le programme Java par définition. Si je spécifie non-lancement, il utilise com.sun.jdi.SocketListen comme je m'y attendais, une fois qu'il a démarré le socket serveur, automatiquement starts a remote vm and connects to this socket. Je pense que c'est inattendu.

Autres choses que j'essayées,

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

je me attends ce échouer ou être bloqué jusqu'à ce qu'un processus distinct commence.

Existe-t-il une autre méthode pour spécifier les connecteurs ou ne pas démarrer une machine virtuelle Java? (Je ne suis pas intéressé par 'local' non plus)

Certaines options faciles comme la possibilité de spécifier com.sun.jdi.RawCommandLineLaunch comme connecteur acceptant la commande personnalisée ou d'utiliser le connecteur d'écoute socket et d'attendre que l'autre processus se connecte.

Merci.

Répondre

1

EDIT: J'ai trouvé un bogue dans ceci - ceci ne devrait pas fonctionner, parce que le JDWP n'est pas attaché à la nouvelle VM.


Oui, cela peut être accompli avec un hack rapide. La version adaptée de my description est la suivante:

Le hack repose sur le remplacement de l'agent dans la machine virtuelle démarrée par JShell. Il peut être injecté par le remoteAgentexecution parameter.

Le nouvel agent factice doit en quelque sorte indiquer le numéro de port auquel il était censé se connecter. Si cela ne vous dérange pas les hacks laids, cela peut être aussi simple que de l'écrire dans un fichier. Vous pouvez également profiter d'un tuyau nommé. Je ne recommanderais pas cela pour quelque chose de sérieux, cependant.

Un agent simple:

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 sur votre ordinateur est le côté d'écoute du canal JDWP. Pour réutiliser l'agent distant existant, vous devez inverser la redirection d'un port choisi vers le côté distant. Ensuite, vous devez exécuter l'agent d'origine du côté distant avec le port distant en tant qu'argument.

En utilisant SSH, il peut ressembler à ceci:

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

Un more robust solution impliquera probablement le clonage des implémentations JdiDefaultExecutionControl et JdiInitiator et leur extension avec une capacité de connexion à distance.