close

Invocation de méthode distante Java

Aller à la navigation Aller à la recherche

RMI ( Java Remote Method Invocation ) est un mécanisme proposé par Java pour invoquer une méthode à distance. Il fait partie de l'environnement d'exécution Java standard et fournit un mécanisme simple pour la communication du serveur dans les applications Java distribuées uniquement. Si une communication entre d'autres technologies est nécessaire, CORBA ou SOAP doit être utilisé à la place de RMI.

RMI se caractérise par sa facilité d'utilisation en programmation car il est spécifiquement conçu pour Java ; fournit le passage d'objet par référence (non autorisé par SOAP), la récupération de place distribuée (Distributed Garbage Collector) et le passage de type arbitraire (fonctionnalité non fournie par CORBA).

Grâce à RMI, un programme Java peut exporter un objet , rendant l'objet accessible sur le réseau et le programme attendant les requêtes sur un port TCP . Par la suite, un client peut se connecter et invoquer les méthodes fournies par l'objet.

L'invocation comprend les étapes suivantes :

  • Classement des paramètres (à l'aide de la fonctionnalité de sérialisation de Java ).
  • Invocation de la méthode (du client sur le serveur). L'appelant attend une réponse.
  • Une fois l'exécution terminée, le serveur sérialise la valeur de retour (le cas échéant) et l'envoie au client.
  • Le code client reçoit la réponse et continue comme si l'appel avait été local.

Contexte

Depuis la version 1.1 du JDK, Java possède son propre ORB : RMI (Remote Method Invocation). Bien que RMI soit un ORB au sens général, ce n'est pas un modèle conforme à CORBA. RMI est natif de Java, c'est-à-dire qu'il s'agit d'une extension du langage de base. RMI repose entièrement sur le cœur de la sérialisation d'objets Java, ainsi que sur la mise en œuvre de la portabilité et des mécanismes de chargement et de déchargement d'objets sur d'autres systèmes, etc.

L'utilisation de RMI est très naturelle pour tout programmeur Java puisqu'il n'a pas à apprendre une nouvelle technologie complètement différente de celle avec laquelle il va développer. Cependant, RMI présente certaines limitations dues à son intégration étroite avec Java, la principale étant que cette technologie ne permet pas d'interagir avec des applications écrites dans un autre langage.

RMI, en tant qu'extension de Java, est une technologie de programmation conçue pour résoudre des problèmes en écrivant et en organisant du code exécutable. Ainsi RMI constitue un point spécifique dans l'espace des technologies de programmation avec C, C++, Smalltalk, etc.

La principale différence entre l'utilisation de RPC et de RMI est que RMI est un mécanisme d'appel de procédure à distance basé sur le langage de programmation Java qui prend en charge l'interaction entre les objets, alors que RPC ne prend pas en charge cette fonctionnalité.

Architecture

L'architecture RMI peut être considérée comme un modèle à quatre niveaux.

Première couche

La première couche est la couche application et correspond à l'implémentation proprement dite des applications client et serveur. Les appels de haut niveau pour accéder et exporter des objets distants ont lieu ici. Toute application qui souhaite que ses méthodes soient accessibles aux clients distants doit déclarer ces méthodes dans une interface qui étend java.rmi.Remote. Une telle interface est essentiellement utilisée pour "marquer" un objet comme accessible à distance. Une fois les méthodes implémentées, l'objet doit être exporté. Cela peut être fait implicitement si l'objet étend la classe UnicastRemoteObject (paquet java.rmi.server), ou cela peut être fait explicitement en appelant la méthode exportObject() du même paquet.

Deuxième couche

La couche 2 est la couche proxy, ou couche stub-skeleton. Cette couche est celle qui interagit directement avec la couche application. Tous les appels aux objets et actions distants ainsi que leurs paramètres et les objets de retour ont lieu dans cette couche.

Troisième couche

La couche 3 est la couche de référence distante et est responsable de la gestion de la partie sémantique des invocations distantes. Il est également responsable de la gestion de la réplication d'objets et de l'exécution de tâches spécifiques à l'implémentation avec des objets distants, telles que l'établissement de la persistance sémantique et des stratégies appropriées pour récupérer des connexions perdues. Dans cette couche, une connexion orientée flux est attendue de la couche transport.

Quatrième couche

La couche 4 est la couche de transport. Il est chargé d'effectuer les connexions nécessaires et de gérer le transport des données d'une machine à l'autre. Le protocole de transport sous-jacent pour RMI est Java Remote Method Protocol (JRMP), qui n'est « compris » que par les programmes Java.

Éléments

Chaque application RMI se décompose normalement en 2 parties :

  • Un serveur, qui crée des objets distants, crée des références pour les rendre accessibles et attend que le client les invoque.
  • Un client, qui obtient une référence à des objets distants sur le serveur, et les appelle.

Exemple

Un serveur RMI consiste à définir un objet distant qui va être utilisé par des clients. Pour créer un objet distant, une interface est définie et l'objet distant sera une classe qui implémente cette interface. Voyons comment créer un exemple de serveur en 3 étapes :

  • Définissez l'interface distante. Lorsqu'une interface distante est créée :
    • L'interface doit être publique.
    • Il doit hériter de l'interface java.rmi.Remote, pour indiquer qu'il peut être appelé depuis n'importe quelle machine virtuelle Java.
    • Chaque méthode distante doit lever l'exception java.rmi.RemoteException dans sa clause throws, en plus de toutes les exceptions qu'elle peut gérer.
 interface  publique MyRemoteInterface  étend  java . rmi . Remote 
{ 
  public  void  myMethod1 ()  lance  java . rmi . RemoteException ; 
  public  int  myMethod2 ()  lance  java . rmi . RemoteException ; 
}
  • Implémenter l'interface distante
 la classe  publique MyRemoteClass  
 étend  java . rmi . serveur . UnicastRemoteObject  
 implémente  MyRemoteInterface 
{ 
 public  MyRemoteClass ()  throws  java . rmi . RemoteException 
 { 
   super ();  //Appelle le constructeur de la classe de base (UnicastRemoteObject) 
   // Code constructeur 
 }
 
 public  void  myMethod1 ()  lance  java . rmi . RemoteException 
 { 
   // Ici, nous mettons le code que nous voulons 
   System . dehors . println ( "Je suis dans maMéthode1()" ); 
 }

 public  int  myMethod2 ()  lance  java . rmi . RemoteException 
 { 
   return  5 ;  // Ici on met le code qu'on veut 
 }

 public  void  otherMethod () 
 { 
   // Si nous définissons une autre méthode, elle ne pourra pas être appelée 
   // à distance car elle ne provient pas de l'interface distante 
 }
 
 public  static  void  main ( String []  args ) 
 { 
   try 
   { 
     MyRemoteInterface  mir  =  new  MyRemoteClass (); 
     Java . rmi . Dénomination . rebind ( "rmi://"  +  java . net . InetAddress . getLocalHost (). getHostAddress ()  + 
                             ":"  +  args [ 0 ]  +  "/TestRMI" ,  mir ); 
   } 
   catch  ( Exception  e ) 
   { 
     e . printStackTrace (); 
   } 
 } 
}
  • Comme vous pouvez le voir, la classe MyRemoteClass implémente l'interface MyRemoteInterface que nous avons précédemment définie. De plus, il hérite de UnicastRemoteObject, qui est une classe Java que nous pouvons utiliser comme superclasse pour implémenter des objets distants.
  • Ensuite, à l'intérieur de la classe, nous définissons un constructeur (qui lève l'exception RemoteException car elle est également levée par la superclasse UnicastRemoteObject), et les méthodes de l'interface ou des interfaces qu'il implémente.
  • Enfin, dans la méthode principale, nous définissons le code pour créer l'objet distant que nous voulons partager et rendre l'objet distant visible aux clients, en utilisant la classe Naming et sa méthode rebind(...) .

Remarque : nous avons placé la méthode main() dans la même classe pour plus de commodité. Une classe distincte pourrait être définie pour être responsable de l'enregistrement de l'objet distant.

  • Compiler et exécuter le serveur

Nous avons déjà défini le serveur. Nous devons maintenant compiler vos classes en suivant les étapes suivantes :

    • Nous compilons l'interface distante. De plus, nous le regroupons dans un fichier JAR pour le garder présent à la fois sur le client et sur le serveur :
javac MyRemoteInterface.java
jar cvf objRemotes.jar MyRemoteInterface.class
    • Ensuite, nous compilons les classes qui implémentent les interfaces. Et pour chacun d'eux nous générons les fichiers Stub et Skeleton pour maintenir la référence à l'objet distant, en utilisant la commande rmic :
définissez CLASSPATH=%CLASSPATH%;.\Remoteobj.jar;.
javac MaClasseDistante.java
rmic -d . MaClasseDistant

Nous pouvons voir dans notre répertoire de travail que deux fichiers .class ont été générés automatiquement (MiClaseRemota_Skel.class et MiClaseRemota_Stub.class) correspondant à la couche stub-skeleton de l'architecture RMI.

  • Pour exécuter le serveur, nous suivons ces étapes :
    • La journalisation RMI est démarrée pour permettre la journalisation et la recherche d'objets distants. Le registre est chargé de gérer un ensemble d'objets distants à partager et de les rechercher à la demande des clients. Il fonctionne avec l'application rmiregistry distribuée avec Java, à laquelle nous pouvons éventuellement transmettre le port de connexion (par défaut, 1099).

Dans le cas de Windows, il faut exécuter :

démarrer le registre rmire 1234

Et dans le cas de Linux :

rmiregistre &
    • Enfin, le serveur est lancé :
java -Djava.rmi.server.hostname=127.0.0.1 MaClasseDistante 1234
  • Créer un client RMI

Nous allons maintenant définir un client qui accédera au(x) objet(s) distant(s) que nous créons. Pour cela nous suivons les étapes suivantes :

    • Définir la classe pour obtenir les objets distants requis

La classe suivante récupère un objet de type MyRemoteInterface, implémenté sur notre serveur :

 classe  publique MyRMIClient 
{

  MonClientRMIC privé (){} ; 

 public  static  void  main ( String []  args ) 
 { 
   try 
   { 
     MyRemoteInterface  mir  =  ( MyRemoteInterface ) java . rmi . Dénomination . recherche ( "rmi://"  +  
                             args [ 0 ]  +  ":"  +  args [ 1 ]  +  "/RMITest" );
     
     // Affiche myMethod1() autant de fois que myMethod2() renvoie 
     for  ( int  i = 1 ; i <= myr . myMethod2 (); i ++ )  
         myr . maMéthode1 (); 
   } 
   catch  ( Exception  e ) 
   { 
     e . printStackTrace (); 
   } 
 } 
}

Comme vous pouvez le voir, cela consiste simplement à rechercher l'objet distant dans le registre RMI de la machine distante. Pour ce faire, nous utilisons la classe Naming et sa méthode lookup(...) .

    • Compiler et exécuter le client

Une fois que nous avons déjà défini le client, pour le compiler nous faisons :

définissez CLASSPATH=%CLASSPATH%;.\Remoteobj.jar;.
javac MyRMIClient.java

Ensuite, pour exécuter le client, nous faisons :

java MyClientRMI 127.0.0.1 1234

Le fichier stub de la classe distante doit être accessible. Pour ce faire, soit nous le copions sur le client et l'incluons dans son CLASSPATH, soit nous le supprimons du CLASSPATH du serveur et incluons son chemin dans le java.rmi.codebase du serveur (s'il n'est pas supprimé du CLASSPATH du serveur, l'option java. rmi.codebase, et le client ne pourra pas accéder au Stub). Si nous regardons la fenêtre où tourne le serveur RMI, nous verrons comment l'objet distant a été trouvé et ses méthodes ont été exécutées :

Voir aussi

Liens externes