Java RMI - Guia rápido

RMI significa Remote Method Invocation. É um mecanismo que permite que um objeto residente em um sistema (JVM) acesse / invoque um objeto em execução em outra JVM.

RMI é usado para construir aplicativos distribuídos; ele fornece comunicação remota entre programas Java. É fornecido no pacotejava.rmi.

Arquitetura de um aplicativo RMI

Em um aplicativo RMI, escrevemos dois programas, um server program (reside no servidor) e um client program (reside no cliente).

  • Dentro do programa servidor, um objeto remoto é criado e a referência desse objeto é disponibilizada para o cliente (usando o registro).

  • O programa cliente solicita os objetos remotos no servidor e tenta invocar seus métodos.

O diagrama a seguir mostra a arquitetura de um aplicativo RMI.

Vamos agora discutir os componentes dessa arquitetura.

  • Transport Layer- Esta camada conecta o cliente e o servidor. Ele gerencia a conexão existente e também estabelece novas conexões.

  • Stub- Um stub é uma representação (proxy) do objeto remoto no cliente. Ele reside no sistema do cliente; ele atua como um gateway para o programa cliente.

  • Skeleton - Este é o objeto que reside no lado do servidor. stub se comunica com este esqueleto para passar a solicitação ao objeto remoto.

  • RRL(Remote Reference Layer) - É a camada que gerencia as referências feitas pelo cliente ao objeto remoto.

Trabalho de um aplicativo RMI

Os pontos a seguir resumem como funciona um aplicativo RMI -

  • Quando o cliente faz uma chamada para o objeto remoto, ele é recebido pelo stub que eventualmente passa essa solicitação para o RRL.

  • Quando o RRL do lado do cliente recebe a solicitação, ele invoca um método chamado invoke() do objeto remoteRef. Ele passa a solicitação para o RRL no lado do servidor.

  • O RRL no lado do servidor passa a solicitação para o Skeleton (proxy no servidor), que finalmente chama o objeto necessário no servidor.

  • O resultado é passado de volta ao cliente.

Marshalling e Unmarshalling

Sempre que um cliente invoca um método que aceita parâmetros em um objeto remoto, os parâmetros são agrupados em uma mensagem antes de serem enviados pela rede. Esses parâmetros podem ser do tipo ou objetos primitivos. No caso do tipo primitivo, os parâmetros são colocados juntos e um cabeçalho é anexado a eles. Caso os parâmetros sejam objetos, eles são serializados. Este processo é conhecido comomarshalling.

No lado do servidor, os parâmetros compactados são descompactados e, em seguida, o método necessário é chamado. Este processo é conhecido comounmarshalling.

Registro RMI

O registro RMI é um namespace no qual todos os objetos do servidor são colocados. Cada vez que o servidor cria um objeto, ele registra esse objeto com o RMIregistry (usandobind() ou reBind()métodos). Eles são registrados usando um nome exclusivo conhecido comobind name.

Para invocar um objeto remoto, o cliente precisa de uma referência desse objeto. Nesse momento, o cliente busca o objeto do registro usando seu nome de ligação (usandolookup() método).

A ilustração a seguir explica todo o processo -

Objetivos do RMI

A seguir estão os objetivos do RMI -

  • Para minimizar a complexidade do aplicativo.
  • Para preservar a segurança do tipo.
  • Coleta de lixo distribuída.
  • Minimize a diferença entre trabalhar com objetos locais e remotos.

Para escrever um aplicativo RMI Java, você teria que seguir as etapas fornecidas abaixo -

  • Defina a interface remota
  • Desenvolva a classe de implementação (objeto remoto)
  • Desenvolva o programa de servidor
  • Desenvolva o programa do cliente
  • Compile o aplicativo
  • Execute o aplicativo

Definindo a Interface Remota

Uma interface remota fornece a descrição de todos os métodos de um determinado objeto remoto. O cliente se comunica com esta interface remota.

Para criar uma interface remota -

  • Crie uma interface que estenda a interface predefinida Remote que pertence ao pacote.

  • Declare todos os métodos de negócios que podem ser chamados pelo cliente nesta interface.

  • Como há uma chance de problemas de rede durante chamadas remotas, uma exceção chamada RemoteExceptionpode ocorrer; jogá-lo.

A seguir está um exemplo de uma interface remota. Aqui definimos uma interface com o nomeHello e tem um método chamado printMsg().

import java.rmi.Remote; 
import java.rmi.RemoteException;  

// Creating Remote interface for our application 
public interface Hello extends Remote {  
   void printMsg() throws RemoteException;  
}

Desenvolvendo a classe de implementação (objeto remoto)

Precisamos implementar a interface remota criada na etapa anterior. (Podemos escrever uma classe de implementação separadamente ou podemos fazer diretamente o programa do servidor implementar esta interface.)

Para desenvolver uma classe de implementação -

  • Implemente a interface criada na etapa anterior.
  • Fornece implementação para todos os métodos abstratos da interface remota.

A seguir está uma classe de implementação. Aqui, criamos uma classe chamadaImplExample e implementou a interface Hello criado na etapa anterior e fornecido body para este método que imprime uma mensagem.

// Implementing the remote interface 
public class ImplExample implements Hello {  
   
   // Implementing the interface method 
   public void printMsg() {  
      System.out.println("This is an example RMI program");  
   }  
}

Desenvolvendo o Programa de Servidor

Um programa de servidor RMI deve implementar a interface remota ou estender a classe de implementação. Aqui, devemos criar um objeto remoto e vinculá-lo aoRMIregistry.

Para desenvolver um programa de servidor -

  • Crie uma classe de cliente de onde você deseja chamar o objeto remoto.

  • Create a remote object instanciando a classe de implementação conforme mostrado abaixo.

  • Exporte o objeto remoto usando o método exportObject() da classe chamada UnicastRemoteObject que pertence ao pacote java.rmi.server.

  • Obtenha o registro RMI usando o getRegistry() método do LocateRegistry classe que pertence ao pacote java.rmi.registry.

  • Vincule o objeto remoto criado ao registro usando o bind() método da classe chamada Registry. Para este método, passe uma string representando o nome do bind e o objeto exportado, como parâmetros.

A seguir está um exemplo de um programa de servidor RMI.

import java.rmi.registry.Registry; 
import java.rmi.registry.LocateRegistry; 
import java.rmi.RemoteException; 
import java.rmi.server.UnicastRemoteObject; 

public class Server extends ImplExample { 
   public Server() {} 
   public static void main(String args[]) { 
      try { 
         // Instantiating the implementation class 
         ImplExample obj = new ImplExample(); 
    
         // Exporting the object of implementation class  
         // (here we are exporting the remote object to the stub) 
         Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0);  
         
         // Binding the remote object (stub) in the registry 
         Registry registry = LocateRegistry.getRegistry(); 
         
         registry.bind("Hello", stub);  
         System.err.println("Server ready"); 
      } catch (Exception e) { 
         System.err.println("Server exception: " + e.toString()); 
         e.printStackTrace(); 
      } 
   } 
}

Desenvolvendo o Programa do Cliente

Escreva um programa cliente nele, busque o objeto remoto e invoque o método requerido usando este objeto.

Para desenvolver um programa de cliente -

  • Crie uma classe de cliente de onde você pretende invocar o objeto remoto.

  • Obtenha o registro RMI usando o getRegistry() método do LocateRegistry classe que pertence ao pacote java.rmi.registry.

  • Busque o objeto do registro usando o método lookup() da classe Registry que pertence ao pacote java.rmi.registry.

    Para este método, você precisa passar um valor de string representando o nome do vínculo como um parâmetro. Isso retornará o objeto remoto.

  • O lookup () retorna um objeto do tipo remote, down cast para o tipo Hello.

  • Finalmente invoque o método requerido usando o objeto remoto obtido.

A seguir está um exemplo de um programa cliente RMI.

import java.rmi.registry.LocateRegistry; 
import java.rmi.registry.Registry;  

public class Client {  
   private Client() {}  
   public static void main(String[] args) {  
      try {  
         // Getting the registry 
         Registry registry = LocateRegistry.getRegistry(null); 
    
         // Looking up the registry for the remote object 
         Hello stub = (Hello) registry.lookup("Hello"); 
    
         // Calling the remote method using the obtained object 
         stub.printMsg(); 
         
         // System.out.println("Remote method invoked"); 
      } catch (Exception e) {
         System.err.println("Client exception: " + e.toString()); 
         e.printStackTrace(); 
      } 
   } 
}

Compilando o aplicativo

Para compilar o aplicativo -

  • Compile a interface remota.
  • Compile a classe de implementação.
  • Compile o programa do servidor.
  • Compile o programa cliente.

Ou,

Abra a pasta onde você armazenou todos os programas e compile todos os arquivos Java como mostrado abaixo.

Javac *.java

Executando o aplicativo

Step 1 - Comece o rmi registro usando o seguinte comando.

start rmiregistry

Isso vai começar um rmi registro em uma janela separada, conforme mostrado abaixo.

Step 2 - Execute o arquivo de classe do servidor conforme mostrado abaixo.

Java Server

Step 3 - Execute o arquivo de classe do cliente conforme mostrado abaixo.

java Client

Verification - Assim que você iniciar o cliente, verá a seguinte saída no servidor.

No capítulo anterior, criamos um aplicativo RMI de amostra. Neste capítulo, vamos explicar como criar uma aplicação RMI onde um cliente invoca um método que exibe uma janela GUI (JavaFX).

Definindo a Interface Remota

Aqui, estamos definindo uma interface remota chamada Hello com um método chamado animation() iniciar.

import java.rmi.Remote; 
import java.rmi.RemoteException;  

// Creating Remote interface for our application 
public interface Hello extends Remote { 
   void animation() throws RemoteException; 
}

Desenvolvendo a Classe de Implementação

Na classe Implementation (Remote Object) desta aplicação, estamos tentando criar uma janela que exibe o conteúdo da GUI, utilizando JavaFX.

import javafx.animation.RotateTransition;  
import javafx.application.Application;  
import javafx.event.EventHandler;   

import javafx.scene.Group;  
import javafx.scene.PerspectiveCamera;  
import javafx.scene.Scene;  
import javafx.scene.control.TextField;  
import javafx.scene.input.KeyEvent;  
import javafx.scene.paint.Color;  
import javafx.scene.paint.PhongMaterial; 
  
import javafx.scene.shape.Box;  
import javafx.scene.text.Font;  
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;   
import javafx.scene.transform.Rotate;  

import javafx.stage.Stage;  
import javafx.util.Duration;  

// Implementing the remote interface 
public class FxSample extends Application implements Hello {  
   @Override  
   public void start(Stage stage) { 
      // Drawing a Box  
      Box box = new Box();  

      // Setting the properties of the Box  
      box.setWidth(150.0);  
      box.setHeight(150.0);    
      box.setDepth(100.0);  

      // Setting the position of the box  
      box.setTranslateX(350);   
      box.setTranslateY(150);  
      box.setTranslateZ(50);  

      // Setting the text  
      Text text = new Text(
         "Type any letter to rotate the box, and click on the box to stop the rotation");

      // Setting the font of the text  
      text.setFont(Font.font(null, FontWeight.BOLD, 15));      

      // Setting the color of the text  
      text.setFill(Color.CRIMSON);  

      // Setting the position of the text  
      text.setX(20);  
      text.setY(50); 

      // Setting the material of the box  
      PhongMaterial material = new PhongMaterial();   
      material.setDiffuseColor(Color.DARKSLATEBLUE);   

      // Setting the diffuse color material to box  
      box.setMaterial(material);        

      // Setting the rotation animation to the box     
      RotateTransition rotateTransition = new RotateTransition();  

      // Setting the duration for the transition  
      rotateTransition.setDuration(Duration.millis(1000));  

      // Setting the node for the transition  
      rotateTransition.setNode(box);        

      // Setting the axis of the rotation  
      rotateTransition.setAxis(Rotate.Y_AXIS);  

      // Setting the angle of the rotation 
      rotateTransition.setByAngle(360);  

      // Setting the cycle count for the transition  
      rotateTransition.setCycleCount(50);  

      // Setting auto reverse value to false  
      rotateTransition.setAutoReverse(false);   

      // Creating a text filed  
      TextField textField = new TextField();    

      // Setting the position of the text field  
      textField.setLayoutX(50);  
      textField.setLayoutY(100);  

      // Handling the key typed event  
      EventHandler<KeyEvent> eventHandlerTextField = new EventHandler<KeyEvent>() {  
         @Override  
         public void handle(KeyEvent event) {  
            // Playing the animation  
            rotateTransition.play();  
         }            
      };               
      
      // Adding an event handler to the text feld  
      textField.addEventHandler(KeyEvent.KEY_TYPED, eventHandlerTextField);  

      // Handling the mouse clicked event(on box)  
      EventHandler<javafx.scene.input.MouseEvent> eventHandlerBox =  
         new EventHandler<javafx.scene.input.MouseEvent>() {  
         @Override  
         public void handle(javafx.scene.input.MouseEvent e) {  
            rotateTransition.stop();   
         }  
      };  
      
      // Adding the event handler to the box   
      box.addEventHandler(javafx.scene.input.MouseEvent.MOUSE_CLICKED, eventHandlerBox); 

      // Creating a Group object 
      Group root = new Group(box, textField, text);  

      // Creating a scene object  
      Scene scene = new Scene(root, 600, 300);       

      // Setting camera  
      PerspectiveCamera camera = new PerspectiveCamera(false);  
      camera.setTranslateX(0);  
      camera.setTranslateY(0);  
      camera.setTranslateZ(0);  
      scene.setCamera(camera);   

      // Setting title to the Stage
      stage.setTitle("Event Handlers Example");  

      // Adding scene to the stage  
      stage.setScene(scene);  

      // Displaying the contents of the stage  
      stage.show();  
   }  

   // Implementing the interface method 
   public void animation() {  
      launch();  
   }  
}

Programa de Servidor

Um programa de servidor RMI deve implementar a interface remota ou estender a classe de implementação. Aqui, devemos criar um objeto remoto e vinculá-lo aoRMIregistry.

A seguir está o programa do servidor deste aplicativo. Aqui, vamos estender a classe criada acima, criar um objeto remoto e registrá-lo no registro RMI com o nome de ligaçãohello.

import java.rmi.registry.Registry; 
import java.rmi.registry.LocateRegistry; 
import java.rmi.RemoteException; 
import java.rmi.server.UnicastRemoteObject; 

public class Server extends FxSample { 
   public Server() {} 
   public static void main(String args[]) { 
      try { 
         // Instantiating the implementation class 
         FxSample obj = new FxSample();
      
         // Exporting the object of implementation class  
         // (here we are exporting the remote object to the stub) 
         Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0);  
      
         // Binding the remote object (stub) in the registry 
         Registry registry = LocateRegistry.getRegistry(); 
         
         registry.bind("Hello", stub);  
         System.err.println("Server ready"); 
      } catch (Exception e) { 
         System.err.println("Server exception: " + e.toString()); 
         e.printStackTrace(); 
      } 
   } 
}

Programa Cliente

A seguir está o programa cliente deste aplicativo. Aqui, estamos buscando o objeto remoto e invocando seu método denominadoanimation().

import java.rmi.registry.LocateRegistry; 
import java.rmi.registry.Registry;  

public class Client { 
   private Client() {} 
   public static void main(String[] args) {  
      try { 
         // Getting the registry 
         Registry registry = LocateRegistry.getRegistry(null); 
    
         // Looking up the registry for the remote object 
         Hello stub = (Hello) registry.lookup("Hello"); 
         
         // Calling the remote method using the obtained object 
         stub.animation(); 
         
         System.out.println("Remote method invoked"); 
      } catch (Exception e) {
         System.err.println("Client exception: " + e.toString()); 
         e.printStackTrace(); 
      } 
   } 
}

Etapas para executar o exemplo

A seguir estão as etapas para executar nosso Exemplo de RMI.

Step 1 - Abra a pasta onde você armazenou todos os programas e compile todos os arquivos Java como mostrado abaixo.

Javac *.java

Step 2 - Comece o rmi registro usando o seguinte comando.

start rmiregistry

Isso vai começar um rmi registro em uma janela separada, conforme mostrado abaixo.

Step 3 - Execute o arquivo de classe do servidor conforme mostrado abaixo.

Java Server

Step 4 - Execute o arquivo de classe do cliente conforme mostrado abaixo.

java Client

Verification - Assim que você iniciar o cliente, verá a seguinte saída no servidor.

No capítulo anterior, criamos um aplicativo RMI de amostra em que um cliente invoca um método que exibe uma janela GUI (JavaFX).

Neste capítulo, daremos um exemplo para ver como um programa cliente pode recuperar os registros de uma tabela no banco de dados MySQL residente no servidor.

Suponha que temos uma mesa chamada student_data no banco de dados details como mostrado abaixo.

+----+--------+--------+------------+---------------------+ 
| ID | NAME   | BRANCH | PERCENTAGE | EMAIL               | 
+----+--------+--------+------------+---------------------+ 
|  1 | Ram    | IT     |         85 | [email protected]    | 
|  2 | Rahim  | EEE    |         95 | [email protected]  | 
|  3 | Robert | ECE    |         90 | [email protected] | 
+----+--------+--------+------------+---------------------+

Suponha que o nome do usuário seja myuser e sua senha é password.

Criando uma classe de aluno

Criar uma Student aula com setter e getter métodos como mostrado abaixo.

public class Student implements java.io.Serializable {   
   private int id, percent;   
   private String name, branch, email;    
  
   public int getId() { 
      return id; 
   } 
   public String getName() { 
      return name; 
   } 
   public String getBranch() { 
      return branch; 
   } 
   public int getPercent() { 
      return percent; 
   } 
   public String getEmail() { 
      return email; 
   } 
   public void setID(int id) { 
      this.id = id; 
   } 
   public void setName(String name) { 
      this.name = name; 
   } 
   public void setBranch(String branch) { 
      this.branch = branch; 
   } 
   public void setPercent(int percent) { 
      this.percent = percent; 
   } 
   public void setEmail(String email) { 
      this.email = email; 
   } 
}

Definindo a Interface Remota

Defina a interface remota. Aqui, estamos definindo uma interface remota chamadaHello com um método chamado getStudents ()iniciar. Este método retorna uma lista que contém o objeto da classeStudent.

import java.rmi.Remote; 
import java.rmi.RemoteException; 
import java.util.*;

// Creating Remote interface for our application 
public interface Hello extends Remote {  
   public List<Student> getStudents() throws Exception;  
}

Desenvolvendo a Classe de Implementação

Crie uma classe e implemente o criado acima interface.

Aqui estamos implementando o getStudents() método do Remote interface. Quando você invoca este método, ele recupera os registros de uma tabela chamadastudent_data. Define esses valores para a classe Student usando seus métodos setter, adiciona-os a um objeto de lista e retorna essa lista.

import java.sql.*; 
import java.util.*;  

// Implementing the remote interface 
public class ImplExample implements Hello {  
   
   // Implementing the interface method 
   public List<Student> getStudents() throws Exception {  
      List<Student> list = new ArrayList<Student>();   
    
      // JDBC driver name and database URL 
      String JDBC_DRIVER = "com.mysql.jdbc.Driver";   
      String DB_URL = "jdbc:mysql://localhost:3306/details";  
      
      // Database credentials 
      String USER = "myuser"; 
      String PASS = "password";  
      
      Connection conn = null; 
      Statement stmt = null;  
      
      //Register JDBC driver 
      Class.forName("com.mysql.jdbc.Driver");   
      
      //Open a connection
      System.out.println("Connecting to a selected database..."); 
      conn = DriverManager.getConnection(DB_URL, USER, PASS); 
      System.out.println("Connected database successfully...");  
      
      //Execute a query 
      System.out.println("Creating statement..."); 
      
      stmt = conn.createStatement();  
      String sql = "SELECT * FROM student_data"; 
      ResultSet rs = stmt.executeQuery(sql);  
      
      //Extract data from result set 
      while(rs.next()) { 
         // Retrieve by column name 
         int id  = rs.getInt("id"); 
         
         String name = rs.getString("name"); 
         String branch = rs.getString("branch"); 
         
         int percent = rs.getInt("percentage"); 
         String email = rs.getString("email");  
         
         // Setting the values 
         Student student = new Student(); 
         student.setID(id); 
         student.setName(name); 
         student.setBranch(branch); 
         student.setPercent(percent); 
         student.setEmail(email); 
         list.add(student); 
      } 
      rs.close(); 
      return list;     
   }  
}

Programa de Servidor

Um programa de servidor RMI deve implementar a interface remota ou estender a classe de implementação. Aqui, devemos criar um objeto remoto e vinculá-lo aoRMI registry.

A seguir está o programa do servidor deste aplicativo. Aqui, vamos estender a classe criada acima, criar um objeto remoto e registrá-lo no registro RMI com o nome de ligaçãohello.

import java.rmi.registry.Registry; 
import java.rmi.registry.LocateRegistry; 
import java.rmi.RemoteException; 
import java.rmi.server.UnicastRemoteObject; 

public class Server extends ImplExample { 
   public Server() {} 
   public static void main(String args[]) { 
      try { 
         // Instantiating the implementation class 
         ImplExample obj = new ImplExample(); 
    
         // Exporting the object of implementation class (
            here we are exporting the remote object to the stub) 
         Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0);  
         
         // Binding the remote object (stub) in the registry 
         Registry registry = LocateRegistry.getRegistry(); 
         
         registry.bind("Hello", stub);  
         System.err.println("Server ready"); 
      } catch (Exception e) { 
         System.err.println("Server exception: " + e.toString()); 
         e.printStackTrace(); 
      } 
   } 
}

Programa Cliente

A seguir está o programa cliente deste aplicativo. Aqui, estamos buscando o objeto remoto e invocando o método chamadogetStudents(). Ele recupera os registros da tabela do objeto de lista e os exibe.

import java.rmi.registry.LocateRegistry; 
import java.rmi.registry.Registry; 
import java.util.*;  

public class Client {  
   private Client() {}  
   public static void main(String[] args)throws Exception {  
      try { 
         // Getting the registry 
         Registry registry = LocateRegistry.getRegistry(null); 
    
         // Looking up the registry for the remote object 
         Hello stub = (Hello) registry.lookup("Hello"); 
    
         // Calling the remote method using the obtained object 
         List<Student> list = (List)stub.getStudents(); 
         for (Student s:list)v { 
            
            // System.out.println("bc "+s.getBranch()); 
            System.out.println("ID: " + s.getId()); 
            System.out.println("name: " + s.getName()); 
            System.out.println("branch: " + s.getBranch()); 
            System.out.println("percent: " + s.getPercent()); 
            System.out.println("email: " + s.getEmail()); 
         }  
      // System.out.println(list); 
      } catch (Exception e) { 
         System.err.println("Client exception: " + e.toString()); 
         e.printStackTrace(); 
      } 
   } 
}

Etapas para executar o exemplo

A seguir estão as etapas para executar nosso Exemplo de RMI.

Step 1 - Abra a pasta onde você armazenou todos os programas e compile todos os arquivos Java como mostrado abaixo.

Javac *.java

Step 2 - Comece o rmi registro usando o seguinte comando.

start rmiregistry

Isso vai começar um rmi registro em uma janela separada, conforme mostrado abaixo.

Step 3 - Execute o arquivo de classe do servidor conforme mostrado abaixo.

Java Server

Step 4 - Execute o arquivo de classe do cliente conforme mostrado abaixo.

java Client