SPRING ... REMOTING
by Farihah
Noushene B.E.,
PART-IV
(PUBLISHED
IN DEVELOPER IQ - September2005)
Spring supports
remoting for six different RPC models:
1. Remote
Method Invocation (RMI)
2. Hessian
3. Burlap
4. HTTP invoker
5. EJB
6. JAX-RPC
In all the
models, services are configured into the application through spring
configuration file as spring managed beans. This is accomplished by using a
proxy factory bean that enable us to wire remote services into the properties of
our beans as if they were local objects.
Spring provides
'RmiProxyFactoryBean' to use the RMI service and 'RmiServiceExporter' to
export any spring managed bean as a RMI service.
For wiring a
Hessian based service to Spring client, Spring's
'HessianProxyFactory Bean'
is used. To export a Hessian Service 'HessianServiceExporter' is used and
similarly for wiring a Burlap service 'BurlapProxyFactoryBean' is used and 'BurlapServiceExporter'
is used to export a burlap service.
For exporting
beans as HTTP invoker services, 'HttpInvokerServiceExporter' is used .To
access an HTTP invoker service 'HttpInvokerProxyFactoryBean' can be used.
Spring provides
two proxy factory beans to access the Enterprise Java Beans. 'LocalStatelessSessionProxyFactoryBean'
is used to access the EJB in the same container(local) and another one is
'SimpleRemoteStatelessSessionProxyFactoryBean'
which is used to access
the remote EJBs.
For all the
above models spring provides service exporter classes that exports Java Beans as
remote service. Spring does not provide any EJB Service Exporter and it provides
four abstract support classes to make the development of Spring enabled EJB.
They are
1.
AbstractMessageDrivenBean to
develop MDBs that accept sources other than JMS.
2.
AbstractJmsMessageDrivenBean to
develop MDBs that accept messages from JMS sources.
3.
AbstractStatelessSessionBean to
develop stateless session bean.
4.
AbstractStstefulSessionBean to
develop stateful session bean.
'JaxRpcPostProxyFactoryBean'
is used to wire a web service into the spring application.
The client
makes calls to the proxy to provide the service and the proxy calls the remote
service on behalf of the client.
--------------------------------------------
Now we shall
see how to wire other RMI services into spring application and also how to
export our own service.
Remote Method
Invocation (RMI) Model:
RMI was first
introduced in JDK 1.1. But
developing and accessing RMI
services involves various steps and also have lookups which makes the code hard
to test. Spring simplifies the RMI by providing a 'proxy factory bean' that
enables us to wire the RMI services into spring application as if they were
local beans. Spring also provides a remote exporter that converts our 'spring
managed beans' into RMI services.
Spring's 'RmiProxyFactoryBean'
is a factory bean that creates a proxy to RMI service. It is declared spring
configuration file under the <bean> tag as follows,
<bean
id="service1"
class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl">
<value>rmi://${hostname}/service1</value>
</property>
<property name="serviceInterface">
<value>service1</value>
</property>
</bean>
The url of the
RMI service is set through the 'serviceUrl' property. The 'serviceInterface'
property specifies the interface that the service implements and only
through that the client invokes methods on the service.
For using the
service the implementation code is
wired to the RMI using the following code,
<bean
id="serviceimpl" class="serviceimpl">
<property name="service1">
<ref bean="service1"/>
</property>
</bean>
-------------------------------------------
First set the
path and classpath as before. Next edit the RMI service.
//f:\springdemo\rmserver.java
import java.rmi.*;
public
interface rmserver
extends Remote
{
String getresult(String s) throws
RemoteException;
}
----------------------------------------------
//f:\springdemo\rmserverimpl.java
import java.rmi.*;
import
java.rmi.server.*;
public class
rmserverimpl extends UnicastRemoteObject
implements rmserver
{
public static void main(String args[])
{
try
{
rmserverimpl ob = new rmserverimpl();
Naming.rebind("rmserver",ob);
System.out.println("ready");
}
catch(Exception e1)
{System.out.println(""+e1);}
}
public rmserverimpl() throws RemoteException
{
System.out.println("constructor ok");
}
public String getresult(String a)
throws RemoteException
{
return "Hai..."+a;
}
}
----------------------------------------------
//f:\springdemo\rmserver.xml
<?xml
version="1.0" encoding="UTF-8"?>
<!DOCTYPE
beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/
spring-beans.dtd">
<beans>
<bean id="rmserver"
class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl">
<value>rmi://localhost/rmserver</value>
</property>
<property name="serviceInterface">
<value>rmserver</value>
</property>
</bean>
<bean id="rmserverimpl"
class="rmserverimpl">
<property name="rmserver">
<ref bean="rmserver"/>
</property>
</bean>
</beans>
---------------------------------------------
//f:\springdemo\rmspring.java
import java.rmi.*;
import
org.springframework.beans.factory.*;
import
org.springframework.beans.factory.xml.*;
import
org.springframework.core.io.*;
public class
rmspring
{
public static void main(String args[])
{
try
{
System.out.println("Wait..");
Resource res
= new ClassPathResource("rmi.xml");
BeanFactory factory =
new XmlBeanFactory(res);
rmserver bean1 = (rmserver) factory.getBean("rmserver");
String r=bean1.getresult(args[0]);
System.out.println(r);
}
catch(Exception e1)
{System.out.println(""+e1);}
}
}
---------------------------------------
To run:
f:\springdemo>javac
rmserver.java
f:\springdemo>javac
rmserverimpl.java
f:\springdemo>rmic
rmserverimpl (To create stub and skeleton)
f:\springdemo>javac
rmspring.java
f:\springdemo>start
rmiregistry (a blank window will appear)
f:\springdemo>java
rmserverimpl
Open another
Window and run the client code by giving the argument
f:\springdemo>java
rmspring "sam"
We will get the
output as:
Wait..
......
Here we have
removed the 'lookup' code in the client side.
-----------------------------------------------------------------
Spring also
supports the server side of RMI. Here the service itself is written with spring
and it is exposed as an RMI service. Here the bean is written as a simple
JavaBean. Also we need not generate the stub and skeleton using 'rmic' command
and manually add it to RMI registry. Instead of these traditional procedure 'RmiServiceExporter'
is used to export any Spring managed bean as an RMI service. It wrapps the
bean in an adapter class. The adapter class is then bound to RMI registry and
the proxies request the service.
<bean
class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="service1">
<ref bean="service1"/>
</property>
<property name="serviceName">
<value>service1</value>
</property>
<property name="serviceInterface">
<value>service1</value>
</property>
</bean>
The 'serviceName property' indicates the name of service and 'serviceInterface'
specifies the interface implemented by the service. There is no need of 'serviceUrl'
here
First set the
path and classpath as before. Next edit the service.
//f:\springdemo\rmservice.java
public
interface rmservice
{
String getresult(String
s);
}
------------------------------------------
//f:\springdemo\rmserviceimpl.java
public class
rmserviceimpl implements
rmservice
{
public static void main(String args[])
{
System.out.println("ready");
}
public rmserviceimpl()
{
System.out.println("constructor ok");
}
public String getresult(String a)
{
return "Hai"+a;
}
}
------------------------------------------
//f:\springdemo\rmservice.xml
<?xml
version="1.0" encoding="UTF-8"?>
<!DOCTYPE
beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/
<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
<value>rmservice</value>
</property>
<property name="serviceName">
<value>service1</value>
</property>
<property name="serviceInterface">
<value>rmservice</value>
</property>
</bean>
</bean>
</beans>
------------------------------------------
//f:\springdemo\rmserviceclient.java
import java.io.*;
import
org.springframework.beans.factory.*;
import
org.springframework.beans.factory.xml.*;
import
org.springframework.core.io.*;
class
rmserviceclient
{
public static void main(String args[])
{
try
{
System.out.println("Wait..");
Resource res = new
ClassPathResource("rmservice.xml");
BeanFactory factory = new XmlBeanFactory(res);
System.out.println("factory created");
rmservice bean1 = (rmservice)factory.getBean("rmservice");
String s = bean1.getresult(args[0]);
System.out.println(s);
}
catch(Exception e1)
{System.out.println(""+e1);}
}
}
---------------------------------------
To run:
f:\springdemo>javac
rmservice.java
f:\springdemo>javac
rmserviceimpl.java
f:\springdemo>javac
rmserviceclient.java
f:\springdemo>java
rmsserviceclient
We will get
Output as:
Wait..
Aug 12, 2002
10:55:07 PM
org.springframework.beans.factory.
xml.XmlBeanDefinitionReader
loadBeanDefinitions
INFO: Loading
XML bean definitions from
class path resource[rmservice.xml]
Aug 12, 2002
10:55:07 PM
org.springframework.beans.factory.
support.AbstractBeanFactory getBean
INFO: Creating
shared instance of
singleton bean 'rmservice'
constructor
ok
Hai...sam
Here the service interface doesn't extend the 'java.rmi.Remote' method
and 'RemoteException' is not thrown by the methods. There is no binding in the implementation
code. Also we can direcly run the client. No run to run 'rmserverimpl'
first. Also there is no need to run the RMI registry.
--------------------------------------