1. Overview

Java Remote Method Invocation allows invoking an object residing in a different Java Virtual Machine. It is a well-established technology yet a little cumbersome to use, as we can see in the official Oracle trail dedicated to the subject.

In this quick article, we’ll explore how Spring Remoting allows to leverage RMI in an easier and cleaner way.

This article also completes the overview of Spring Remoting. You can find details about other supported technologies in the previous installments: HTTP Invokers, JMS, AMQP, Hessian, and Burlap.

2. Maven Dependencies

As we did in our previous articles, we’re going to set up a couple of Spring Boot applications: a server that exposes the remote callable object and a client that invokes the exposed service.

Everything we need is in the spring-context jar – so we can bring it in using whatever Spring Boot helper we prefer – because our main goal is just to have the main libraries available.

Let’s now go forward with the usual spring-boot-starter-web – remembering to remove the Tomcat dependency to exclude the embedded web service:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>

3. Server Application

We’ll start declaring an interface that defines a service to book a ride on a cab, that will be eventually exposed to clients:

public interface CabBookingService {
    Booking bookRide(String pickUpLocation) throws BookingException;
}

Then we’ll define a bean that implements the interface. This is the bean that will actually execute the business logic on the server:

@Bean 
CabBookingService bookingService() {
    return new CabBookingServiceImpl();
}

Let’s continue declaring the Exporter that makes the service available to clients. In this case, we’ll use the RmiServiceExporter:

@Bean 
RmiServiceExporter exporter(CabBookingService implementation) {
    Class<CabBookingService> serviceInterface = CabBookingService.class;
    RmiServiceExporter exporter = new RmiServiceExporter();
    exporter.setServiceInterface(serviceInterface);
    exporter.setService(implementation);
    exporter.setServiceName(serviceInterface.getSimpleName());
    exporter.setRegistryPort(1099); 
    return exporter;
}

Through setServiceInterface() we provide a reference to the interface that will be made remotely callable.

We should also provide a reference to the object actually executing the method with setService(). We then could provide the port of the RMI registry available on the machine where the server runs if we don’t want to use the default port 1099.

We should also set a service name, that allows identifying the exposed service in the RMI registry.

With the given configuration the client will be able to contact the CabBookingService at the following URL: rmi://HOST:1199/CabBookingService.

Let’s finally start the server. We don’t even need to start the RMI registry by ourselves because Spring will do that automatically for us if such registry is not available.

4. Client Application

Let’s write now the client application.

We start declaring the RmiProxyFactoryBean that will create a bean that has the same interface exposes by the service running on the server side and that will transparently route the invocations it will receive to the server:

@Bean 
RmiProxyFactoryBean service() {
    RmiProxyFactoryBean rmiProxyFactory = new RmiProxyFactoryBean();
    rmiProxyFactory.setServiceUrl("rmi://localhost:1099/CabBookingService");
    rmiProxyFactory.setServiceInterface(CabBookingService.class);
    return rmiProxyFactory;
}

Let’s then write a simple code that starts up the client application and uses the proxy defined in the previous step:

public static void main(String[] args) throws BookingException {
    CabBookingService service = SpringApplication
      .run(RmiClient.class, args).getBean(CabBookingService.class);
    Booking bookingOutcome = service
      .bookRide("13 Seagate Blvd, Key Largo, FL 33037");
    System.out.println(bookingOutcome);
}

It is now enough to launch the client to verify that it invokes the service exposed by the server.

5. Conclusion

In this tutorial, we saw how we could use Spring Remoting to ease the use of RMI that otherwise will require a series of tedious tasks as, among all, spinning up a registry and define services using interfaces that make heavy use of checked exceptions.

As usual, you’ll find the sources over on GitHub.