Distributed communication with RMI (EJB 3)

Java RMI made its debut very early in Java’s history. (also known Java Remote Method Protocol (JRMP)). It became clear that, as a platform that touts the distributed computing mantra "The network is the computer," Java must provide a simple and robust mechanism for communication across JVM instances. Ideally, method calls on an object running in one JVM should be executed transparently in another remote JVM. With the help of a small amount of boilerplate setup code combined with a few code-generation tools, RMI delivers on this promise. To invoke an object method remotely using RMI, you must

■ Register the remote object implementing the method with an RMI registry.

■ Look up the remote object reference from the registry (the remote reference is accessed through an interface).

■ Invoke the remote method through the reference obtained from the registry.

The idea of a registry to store remote object references is central to RMI. All objects that need to be invoked remotely must be registered with an RMI registry. In order to be registered with an RMI server and be invoked remotely, an object must extend a few RMI classes as well as implement a remote interface. A remote interface defines the object methods that can be invoked remotely. Like the target remote object itself, a remote interface must extend a few RMI interfaces.

Once a remote object is registered with a registry, any client that can access the registry can obtain a reference to it. To get a reference to a remote object, the client must retrieve it from the registry by name and then invoke it through the remote interface. Each time a client invokes a method through the remote interface, the method invocation request is carried transparently across the wire to the remote object. The remote object method is then executed inside its own JVM.


The result of the method invocation (such as a return value) is transported back across the network to be delivered to the client by RMI.

To better understand what is happening in the remote interface scenario, let’s draw an analogy with something familiar to all of us: a television. Think of a television as the remote object to be called. The remote control for our television is the remote interface. The infrared protocol sent by the remote control and picked up by the television is like the RMI protocol. While using the remote control, we don’t have to know all of the details of how the infrared signal works; all we need to know is what each of the buttons on the remote does (the interface methods). Figure A.1 shows how a typical RMI invocation scenario works.

The parallels between EJB and RMI are obvious. Like the EJB object discussed in topic 5, RMI works through proxies on both the client and remote object endpoints to transparently provide distributed computing as a service. In the EJB world, the business interface plays the same role as the "remote" interface, while the EJB bean itself is the "remote object." Just as RMI handles the communication details between the remote client and the object, the container handles the communication details between the EJB client and the managed bean. Before EJB 3, the linkages between RMI and EJB were even more obvious—for example, remote business interfaces had to put java.rmi.RemoteException in their throws clause. In EJB 3, the fact that EJB uses RMI for remoting is rightfully hidden far behind the API as an implementation detail you can safely ignore.

Communication between the RMI client and server (remote object). The RMI server binds an object in the RMI registry. The client performs a lookup in the RMI registry to get a reference to the remote object and then invokes the method on the remote object through the remote interface.

Figure A.1 Communication between the RMI client and server (remote object). The RMI server binds an object in the RMI registry. The client performs a lookup in the RMI registry to get a reference to the remote object and then invokes the method on the remote object through the remote interface.

When you annotate a session bean business interface using the @Remote annotation as we did in topics 2 and 3, the container automatically makes the bean callable via RMI as a remote object. Similarly, when you inject a remote bean using the @EJB annotation, the container talks to the bean through RMI under the hood.

The greatest benefit for RMI is that it provides location transparency. The client invokes methods on a remote object as if the object were located in the same virtual machine, without having to worry about the underlying plumbing. This also means that RMI is generally a lot easier to use and flexible compared to writing TCP/IP sockets by hand for remote communication.

As compelling as RMI might seem from our very high-level discussion, like all technologies it has its own set of problems.

Remote object invocation uses pass-by-value semantics. When the client passes a parameter to the remote method, RMI sends the data held by the object across the network as a byte stream. The byte stream is received by RMI on the other end of the communication tunnel, copied into an object of the same type as passed in by the client, and weaved in as a parameter to the remote object. Objects returned by the remote method go through the same translation-transport-translation steps. The process of turning an object into a byte stream is called marshaling, and the process of turning a byte stream into an object is called unmarshaling. This is exactly why all objects transported across the network by RMI must implement the java.io.Serializable interface. For large objects, the cost of marshaling and unmarshaling can be pretty high, making RMI a performance bottleneck compared to local invocation. This is why you want to make sure that objects passed over RMI are not large, because they can slow down your application.

Like EJB 2, RMI isn’t too easy to use. You often find yourself performing functions such as extending obscure interfaces or classes, and following a strange programming model. Luckily, EJB 3 does all the hard work of generating RMI code behind the scenes.

Last but not least, RMI is great for Java-to-Java transparent communication but is not good for interoperability with Microsoft .NET and the like. If interoperability is a concern, you should be using web services instead of RMI. Note, however, web services is overkill if not absolutely needed, primarily because text-based, parsing-intensive XML performs much worse than binary-based protocols like RMI. Moreover, it is possible to use RMI-IIOP to interoperate between Java and CORBA components written in languages like C+ + . Every EJB container must support RMI-IIOP and enabling RMI-IIOP is simply a matter of configuration.

Next post:

Previous post: