May 21, 2019
Hot Topics:

Understanding Java RMI Internals

  • January 6, 2005
  • By Ahamed Aslam.K
  • Send Email »
  • More Articles »

Source code of CalcClient.java:

import java.rmi.Naming;

public class CalcClient
   public static void main(String[] args)throws Exception
      Calc c=(Calc)Naming.lookup("rmi://remotehost:1099/calc");
Note: You have to replace remotehost with the host name or IP address of the server machine.

These are the classes. Compile all the java files to get the class files. Now, use the RMI compiler to generate the stub. Use the .keep option if you need the source file of the stub.

C:\test>rmic .keep CalcImpl

This will create two files: CalcImpl_Stub.class and CalcImpl_Stub.java.

Source code for CalcImpl_Stub.java:

public final class CalcImpl_Stub
   extends java.rmi.server.RemoteStub
   implements Calc, java.rmi.Remote
   private static final long serialVersionUID = 2;
   private static java.lang.reflect.Method $method_add_0;
   static {
      try {
         $method_add_0 = Calc.class.getMethod("add",
            new java.lang.Class[] {int.class, int.class});
      } catch (java.lang.NoSuchMethodException e) {
         throw new java.lang.NoSuchMethodError(
            "stub class initialization failed");

   // constructors
   public CalcImpl_Stub(java.rmi.server.RemoteRef ref) {

   // methods from remote interfaces

   // implementation of add(int, int)
   public int add(int $param_int_1, int $param_int_2)
      throws java.rmi.RemoteException

      try {
         Object $result = ref.invoke(this, $method_add_0,
                          new java.lang.Object[]
                          {new java.lang.Integer($param_int_1),
                          new java.lang.Integer($param_int_2)},
      return ((java.lang.Integer) $result).intValue();
      } catch (java.lang.RuntimeException e) {
         throw e;
      } catch (java.rmi.RemoteException e) {
         throw e;
      } catch (java.lang.Exception e) {
         throw new java.rmi.UnexpectedException("undeclared checked
                                                 exception", e);

Right now, just don't worry much about what it does; just have a look at the constructor, which you might need later.

Now to run this code on the server machine, we need two consoles.

On console 1, run


On console 2, run

C:\test>java CalcImpl

On the client machine, run the following on a console,

C:\test>java CalcClient

You will get an output of 7 on your screen.

What Is Happening Here

I'll show you what is really happening behind the scenes.

  1. First, RMIRegistry is run on the server machine. RMIRegistry itself is a remote object. The point to note here is this: All remote objects (in other words, all objects that extend UnicastRemoteObject) export themselves to an arbitrary port on the server machine. Because RMIRegistry is also a remote object, it exports itself into a port. A difference is that the the port is a well-known port. By default, it is 1099. The term well-known means that the port is known to all the clients.
  2. Now, the server is run on the server machine. In UnicastRemoteObject's constructor, it exports itself to an anonymous port on the server machine. This port is unknown to the clients; only the server knows about this port.
  3. When you call Naming.rebind(), you are passing a reference of CalcImpl (here c) as the second parameter to the Naming class. The Naming class constructs an object of the Stub and binds it past the stub object (not the actual object) to the Registry remote object. How is the stub object created? Here it is:
    1. The naming class uses the getClass() method to get the name of the class (here, CalcImpl).
    2. Then, it adds _Stub to the name of the class to get the stub's name (here, CalcImpl_Stub).
    3. It loads the CalcImpl_Stub class to the JVM.
    4. It gets a RemoteRef obj from c.
    5. RemoteRef ref=c.getRef();
      It is this ref that encapsulate all the details about the server such as server hostname, server's listening port, address, and so on.
    6. It uses this RemoteRef object to construct the stub:
    7. CalcImpl_Stub stub=new CalcImpl_Stub(ref);

      If you look at CalcImpl_Stub.java, you will find that the stub's constructor takes RemoteRef reference as the parameter.

    8. It passes this stub object to RMIRegistry for binding, along with the public name as (calc,stub).
    9. RMIRegistry stores this public name and stub object in a hashmap internally.
  4. When the client executes Naming.lookup(), it passes the public name as the parameter. The RMIRegistry (which itself is a remote object) returns the stored stub object back to the client. Now, the client gets a stub object that knows about the server host name and port to which the server listens. The client can invoke the stub's method to call the remote object's method.

Page 2 of 3

Comment and Contribute


(Maximum characters: 1200). You have characters left.



Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date