Spring by examples – RMI

RMI is just one of the strategies that you can choose from when you want to implement remoting in your Spring application. At the moment, Spring provides support for Hessian, Burlap, RMI, Web services and an own HTTP remoting solution. All of these remoting strategies were designed so they can share a common configuration style allowing you to manage the exporting and accessing method from outside your business code, in the well known non-intrusive Spring manner. This means that Spring offers a POJO-based programming model for both your server and client, no matter which remoting solution you choose. The reference documentation regarding the remoting features of Spring is available here.

For now we will take a look at how Spring handles RMI while peeking into the code of a small demo application. Our example contains a simple delivery service exposed through a DeliveryServiceIntf interface that has two methods for handling Delivery objects. Below is some of the code for these objects.

public class Delivery implements Serializable {

    private String requesterName;
    private Date deliveryDate;

    public Delivery(String requesterName, Date deliveryDate) {
        this.requesterName = requesterName;
        this.deliveryDate = deliveryDate;
    }
    ...
}

public interface DeliveryServiceIntf {

    void newDelivery(Delivery delivery);

    List getDeliveries();

}

As you can see, the service interface does not need to extend the java.rmi.Remote in order to be used as an RMI service. Also, it’s remotely accessible methods don’t need to throw java.rmi.RemoteException. This is a Spring enhancement that applies to all it’s remoting solutions, not just to RMI. But this is no reason to get scared, because Spring will manage the invocation failure in it’s own fashion by throwing a org.springframework.remoting.RemoteAccessException. This is an unchecked exception so the client can decide if it wants to catch and handle this exception or just ignore it when it’s occurrence it’s considered fatal. This is however Spring’s recommended approach, but you can also expose traditional RMI implementations with Spring. Actually, this is an important issue that you should consider and analyze when remoting with Spring. While both traditional and Spring-managed RMI clients can access a traditional RMI server implementation exported through Spring, only a Spring client will be able to access a Spring exported RMI service that uses a POJO-based model.
Getting back to our example, we have below the implementation of our service which I tried to keep as simple as possible:

public class DeliveryServiceImpl implements DeliveryServiceIntf {

    private List deliveries = new ArrayList();

    public void newDelivery(Delivery delivery) {
        deliveries.add(delivery);
    }

    public List getDeliveries() {
        return deliveries;
    }
}

After we have everything implemented on the server side, we need to configure Spring to export the service through RMI. The following Spring configuration snippet does just that.

    <bean id="deliveryService" class="com.test.rmi.server.DeliveryServiceImpl">        
    </bean>

    <bean class="org.springframework.remoting.rmi.RmiServiceExporter">
        <property name="serviceName" value="delivery-service"/>
        <property name="service" ref="deliveryService"/>
        <property name="serviceInterface" value="com.test.rmi.common.DeliveryServiceIntf"/>
        <property name="registryPort" value="1234"/>
    </bean>

This is the point where we can choose which one of Spring’s remoting solutions we want to adopt. In our case we will use org.springframework.remoting.rmi.RmiServiceExporter which will also manage the RMI registry for us. The serviceName and registryPort properties are RMI specific settings that will constitute the information the client side needs to access our service. The URL for the service in this case will look something like rmi://hostname:1234/delivery-service. The serviceInterface property indicates the POJO whose methods will be the subject of RMI invoking and the service property references a bean implementing the business logic of the service.
At this point, having all up-and-running on the server side requires a small amount of effort and it only consists of classic Spring context initialization.

public class RmiServerTest {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("com/test/rmi/server/rmi-server-context.xml");        
    }
}

Now let’s see how does it work on the client side and how should we proceed to access the remote service. Here is actually a little bit easier because everything relies on the Spring bean configuration file, as seen below, while the rest of the code is pretty straightforward.

    <bean id="deliveryService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
        <property name="serviceUrl" value="rmi://localhost:1234/delivery-service"/>
        <property name="serviceInterface" value="com.test.rmi.common.DeliveryServiceIntf"/>
    </bean>

As you can see, we just need to define the deliveryService bean of class org.springframework.remoting.rmi.RmiProxyFactoryBean. This will indicate Spring that the deliveryService bean will actually be a proxy accessing the remote service at the URL rmi://localhost:1234/delivery-service, and that the business logic of the service will be used by the client through the methods of the DeliveryServiceIntf interface.
Accessing this bean will create a proxy that we can cast to the DeliveryServiceIntf interface and that will dispatch all the calls on this interface to the RMI service. Below is the pretty self-explanatory client-side code.

public class RmiClientTest {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("com/test/rmi/client/rmi-client-context.xml");
        DeliveryServiceIntf deliveryService = (DeliveryServiceIntf) ctx.getBean("deliveryService");
        deliveryService.newDelivery(new Delivery("John Doe", new Date()));
        ...
    }
}

Therefore, the client will not be aware of the fact that the service is running remote and even less about the fact that its method calls are marshaled through RMI. The Spring bean configuration file takes care of these details, so the client code will not be affected if we change the remoting strategy or even if we choose to run the service in-process.

The code for this demo can be found here. The first step is to run ant run-server in order to launch the RMI server and afterwards you need to run ant run-client from another console to start up the RMI client.
Hope this post can give you a basic feeling about Spring’s RMI support. Please feel free to comment on any aspect of this article.

30 comments ↓

#1 mircea ciorba on 11.02.06 at 8:28 am

good one. well written. example runs without any problems.
two thumbs up. ;)

#2 Ayyappan on 07.09.07 at 9:07 am

hi,
how to implement RMI in Spring using net beans IDE.i am new to this environment.tell me how to build and run RMI in netbeans IDE

#3 Surender on 09.12.07 at 7:42 am

A Very clean and professional looking example.
Was very helpful in getting a good understanding the concepts.

Any idea of how we can stop the rmiregistry that gets started without using Ctrl-C in Windows
Despite using Ctrl-C the java process does not get killed.

#4 Rupayan Dutta on 10.24.07 at 12:09 am

I am trying to communicate two j2ee application running on two different instances of Tomcat server via Spring RMI support. I need to pass my complex custom java objects between this two application how can i do that?

The above application doesnot show that. Please give me a solution

#5 Cosmin Marginean on 10.24.07 at 12:50 am

Regarding passing your objects through RMI all you have to do is make sure they implement Serializable and then you can just use them as return values or method parameters. As for Tomcat-to-Tomcat this is something that you should investigate on your own, as there can be several approaches and architectural decisions that might influence your implementation. Since you already use Tomcat as a container I would suggest to consider an HTTP based approach for remoting, like the other protocols that Spring supports (HTTP Invoker, etc) or even webservices. However, you should read the documentation for these to see which one best fits your needs.

#6 prabu vharapu on 10.25.08 at 3:19 pm

run-server:
[java] log4j:WARN No appenders could be found for logger (org.springframewo
rk.core.CollectionFactory).
[java] log4j:WARN Please initialize the log4j system properly.

have this msg while trying to run your application -server

Any ideea how to fix this log4j?

#7 Cosmin Marginean on 10.26.08 at 4:00 am

This is just a log4j issue indicating that log4j is not configured for org.springframewo
rk.core.CollectionFactory. You can ignore it as it has nothing to do with the actual functionality. However, if you are interested, you can learn more about log4j here: http://logging.apache.org/log4j/

#8 Adrian on 10.31.08 at 10:41 am

Well written. Works perfectly.

Thanks

#9 spring-lover on 12.16.08 at 3:56 am

Thanks a millioon times.. i was so confused, on how to do Spring RMI , until i found this valuable, well written and error-free article.. keep it up .. !! thanks a lot once again ..

#10 Cosmin Marginean on 12.16.08 at 4:06 am

Hey “spring-lover”:).
Thanks for the kind words. Even if it’s kind of old, I’m glad you could find it useful.

#11 Siva on 12.25.08 at 6:08 am

Thanks for the useful introductory example.

However, my joy is no more after reading your comment of the example being “kind of old”. I am curious to find about any recent examples which you have placed on the net related to Spring Remoting. If so, sharing of URL would do a lot of good for us.

Thanks, again.

#12 Cosmin Marginean on 12.25.08 at 6:25 am

Well, this sample is old as in “posted very long ago and RMI is not that widely used nowadays”, but it is still compatible with the Spring stack.

As far as I can tell, RMI remoting is done pretty much the same way, even in Spring 2.5.x (here).
I didn’t check in detail, but I don’t think there’s any new/annotation-driven solution to this.

In other words, this should still work great on the latest versions of the framework :) .

#13 reddy on 02.03.09 at 4:51 pm

Its very good example for Spring and RMI.

#14 Cosmin Marginean on 02.03.09 at 6:28 pm

Thank you. Glad you found it useful. :)

#15 Guillermo on 02.06.09 at 5:11 am

Great post!
I found it very useful. I have read the method intercetors one and it’s great too.
Hope you have some time to keep on posting more articles like this ones.

Regards

#16 meng hanyang on 03.30.09 at 1:42 am

please tell :what to do ,spring rmi callback!!

#17 Cosmin Marginean on 03.30.09 at 3:00 am

If you are asking about RMI callbacks in the traditional sense ( http://www.ryerson.ca/~dgrimsha/courses/cps841/RMICallbacks.html , http://www.javaworld.com/javaworld/javaqa/1999-04/05-rmicallback.html ), then unfortunately I don’t know an answer for that. AFAIK there is no straightforward solution to do this with Spring, but I assume there should be some workarounds.

#18 said on 04.02.09 at 5:11 am

“run ant run-server ” ??? how can I do that?? could you please give me a LINK. i do not realise run server

#19 Cosmin Marginean on 04.02.09 at 5:16 am

It means: from the command line, execute:

ant run-server

You must of course have Ant installed and available in PATH.

#20 John Mag on 04.21.09 at 9:32 am

Hi..

I’m using Spring Framework only for persistence proposes and I want to use RMI in the traditional way like in this tutorial (http://java.sun.com/docs/books/tutorial/rmi/index.html).
I’ve developed a RMI server and client without using the Spring Framework features. Now I’m getting a timeout exception when the client tries to invoke the method of the remote object. My doubt is if this problem has nothing related with Spring Framework and is just a simple question of RMI.
In other words, my servers uses intenally the Spring Framework for persistence of objects, but for RMI I don’t used the Spring Framework, there is any problem doing that?

Thanks

#21 Cosmin Marginean on 04.21.09 at 11:29 pm

I don’t believe your problems are caused by the Spring framework, but you never know. Since you get a timeout exception my guess is that you have some port/communication issues, so you might want to check the listening ports of the server, if someone isn’t already binding there, etc.

#22 lourival silva on 06.09.09 at 4:48 am

Thank you very much Cosmin!

Your example helped me a lot.

Congratulations for so good job.

#23 Pratim SC on 06.22.09 at 1:48 pm

A great post.

A no non-sense post. Anyone will grasp the concept of RMI.

Thanks!!! It helped me find issue with my own code :)

#24 said on 07.03.09 at 1:09 am

thank you ths is perfect

#25 LnddMiles on 07.21.09 at 10:12 am

Great post! I’ll subscribe right now wth my feedreader software!

#26 MichaellaS on 07.21.09 at 2:32 pm

tks for the effort you put in here I appreciate it!

#27 Hamed Taghani on 09.07.09 at 10:21 pm

Thanks for this useful article.
I have an question about is any timeout concern in server if the service is take long time. for examle have an time-out property to set acceptable time to get the service.

thank you very much

#28 Cosmin Marginean on 09.07.09 at 10:34 pm

Related to the timeout, my only guess is to overwrite the registryClientSocketFactory property of the RmiProxyFactoryBean’s instance with your own implementation of RMIClientSocketFactory. You can override the createSocket method and just set a timeout on the one created by default.
It’s just a guess but it’s worth a shot.

#29 TechSawi on 04.30.10 at 7:52 am

Hi,

Wonderful example, solved my query in just 1 minute. One query though. What if server class is run as main, I mean not through context loading. I got error but would like to know is it possible?

#30 Derren Weekes on 06.25.10 at 9:17 am

Nice example, however it uses a singleton bean. Anyway I can do this easily using a non-singleton.

I have a “pool” that will get many instances of “worker” (each in its own thread) at run time … the thing that gives work to the workers needs to use rmi so that the “addwork” method runs in the thread, not the dispatcher, hence the DB transactionality is correct in the right thread.

Leave a Comment