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