O RMI (Remote Method Invocation ou Invocação de Método Remoto) é uma interface de programação que permite a exe-
cução de chamadas remotas desenvolvidas em Java. Para entender melhor, leia sobre os seguintes assuntos:
Arquitetura Cliente-Servidor
Serialização
Stub e Skeleton
Funcionamento RMI
Para entendermos como funciona a Invocação do Método Remoto é necessário conhecer o funcionamento da arquitetura Cliente-Servidor.
O modelo cliente-servidor é uma estrutura de aplicação que distribui as tarefas entre os fornecedores de recurso,designados como servidores,
os requerentes de serviços, designados como clientes.
Um servidor é um “host” que pode executar um ou mais serviços que compartilham recursos com os clientes. Um cliente não compartilha
nenhum recurso,mas solicita um conteúdo ou função do servidor. São os clientes que iniciam sessões de comunicação com os servidores,
esses que aguardam requisições de entrada. Ou seja, o cliente faz um pedido para o servidor pelo seu endereço IP e à porta TCP/IP que
designa um serviço específico do servidor. Em seguida, o servidor recebe o pedidoe responde com a ajuda do endereço da máquina cliente
e de sua porta.
Um exemplo prático e de fácil entendimento é o HTTP, assista o vídeo abaixo para entender como ele funciona:
O processo de serialização de objetos é bastante utilizado em sistemas distribuídos, pois com a transformação do objeto
em bytes é possível enviá-lo por uma rede. Depois que um objeto é serializado ele pode ser gravado em um arquivo de
dados e posteriormente disserializado para recriar o objeto na memória. Ou seja, a serialização resume-se em salvar,
gravar, capturar o estado de um objeto.
A serialização é essencial quando se fala de RMI. Caso quiséssemos passar um objeto a um método remeto ou retornar
um objeto desde o servidor até o cliente, o processo seria bem complexo. A passagem de um objeto implica copiar
todo o objeto da sua localização original até a máquina de destino. Utilizando a serialização, só é preciso fazer
a desserialização e recriar o objeto que está na memória.
A figura abaixo mostra o processo geral de serialização:
O RMI utiliza o mecanismo de stub e skeletons para se comunicar com objetos remotos. Ou seja, essa camada é
a responsável por receber as chamadas de métodos feitas pelo cliente através da interface e encaminhá-las para o
objeto remoto.
O stub é uma classe utilizada pela aplicação do cliente e funciona como um proxy entre a aplicação cliente e o
objeto remoto. Os parâmetros dos métodos são passados para a classe skeleton, que é utilizada para a aplicação
do servidor. A classe skeleton recebe esses parâmetros enviados pelo stub e executa as chamadas no objeto remoto.
O funcionamento de RMI consiste basicamente em dois programas, um seria o cliente e outro o servidor. O servidor
instancia objetos remotos, o referencia com um nome e faz um “BIND” dele em uma porta, onde este objeto espera por
clientes que invoquem os seus métodos. Já o cliente referencia remotamente um ou mais métodos de um objeto remoto.
O RMI é quem fornece o mecanismo para que a comunicação entre cliente e servidor seja possível.
Uma aplicação distribuída utiliza o mecanismo “rmiregistry” para obter as referências de objetos remotos.
A imagem abaixo ilustra como uma aplicação RMI utiliza o “rmiregistry”:
O cliente procura o objeto remoto pelo seu nome no registro do servidor e então invoca um método nele. É possível
observar através da imagem que o RMI também pode utilizar um servidor web para carregar os “bytecodes”, de servidor
para cliente e vice-versa.
Para exemplificar o uso do RMI em Java, será mostrado como criar a versão distribuída do clássico programa “Olá Mundo!”, usando
um simples cliente para fazer uma invocação de método remoto de um servidor que pode estar rodando em um hospedeiro remoto.
Passos para criar a aplicação Java RMI:
1. Criar uma interface Remote:
package exemplo.ola;
import java.rmi.Remote
import Java.rmi.RemoteException;
public interface Ola extends Remote{
String digaOla() throws RemoteException;
}
A interface remota precisa declarar o método que você deseja chamar remotamente e estender a interface Java.rmi.Remote.
2. Criar uma classe Servidor
Package exemplo.ola;
Import Java.rmi.registry.Registry;
Import Java.rmi.registry.LocateRegistry;
Import Java.rmi.RemoteException;
Import Java.rmi.server.unicastRemoteObject;
Public class Servidor implements Ola {
Public Servidor(){}
Public string digaOla(){
Return “Ola Mundo!”
}
Public static void main (String args[]){
Try{
//Criação e exportação do Objeto Remoto:
Servidor obj = new Servidor();
Ola stub = (Ola) UnicastRemoteObject.exportObject(obj,0);
//Registro do Objeto Remoto com Java RMI Registry:
Registry registry = LocateRegistry.getRegistry();
Registry.bind(“Ola”,stub);
System.err.println(“Servidor pronto . . .”);
}catch (Exception e){
System.err.println(“Exceçao no servidor: ” + e.toString());
e.printStackTrace();
}
}
}
Essa classe irá implementar a interface Remota. Além disso, ela irá conter o método main, que instancia a implementação do
objeto remoto, exporta o objeto remoto, e associa essa instância a um nome no registro do Java RMI(RMI Registry).
3. Criar uma classe Cliente que faça a invocação do método remoto
Package exemplo.ola;
Import Java.rmi.registry.LocateRegistry;
Import Java.rmi.registry.Registry;
Public class Cliente{
Private Cliente(){}
Public static void main(String[] args){
//hospedeiro(host) do servidor: (null representa host local)
String host = (args.length < 1) ¿ null: args[0];
Try{
//obtém o stub para o registro
Registry registry = LocateRegistry.getRegistry(host);
//obtém o stub para o objeto remoto(Ola) do registro:
Ola stub = (Ola) registry.lookup(“Ola”);
//Invoca o método remoto:
String reposta = stub.digaOla();
System.out.println(“reposta: ” + resposta);
} catch (Exception e) {
System.err.println(“Exceção no cliente” + e.toString());
e.printStackTrace();
}
}
}
Essa classe irá invocar o método remoto. Isso é feito por meio da obtenção do stub
para o registro (registry) no hospedeiro(host) do servidor, procurando o stub do objeto remoto pelo nome no registro,
e por fim invocando o método digaOla() no objeto remoto utilizando o stub.
Quando feita a invocação do método remoto, o programa do cliente abre a conexão com o servidor utilizando as informações
de hospedeiro e porta do stub do objeto remoto e serializa os dados de chamada. O programa do servidor aceita a chamada,
encaminha para o objeto remoto e serializa o resultado (nesse caso a String “Ola Mundo!”) enviando para o Cliente, o qual
retorna o resultado para o método (nesse caso, imprimindo a String em tela).
4. Compilar e rodar o programa
Os comandos utilizados nessa etapa são para sistemas UNIX, podendo também ser realizada com comandos diferentes em outros
sistemas como Windows.
1º passo – Compilar:
2º passo - Gerar o Stub da classe Servidor:
3º passo - Inicializar o registro (RMI Registry) e executar o programa Servidor:
Feito isso, o servidor está pronto, esperando a solicitação de um cliente, e só será terminado caso esse terminal seja fechado. O cliente será executado em
outro terminal, ou seja, em outra máquina virtual Java, e a comunicação será feita por RMI.
A execução do programa do Cliente com o Servidor em funcionamento, finalmente imprimindo a String esperada em tela é apresentada na figura abaixo: