| | + title | Ref. /chapter[1]/title[1] |
| Original | Traduction | Remoting and web services using Spring |
| sect1
| | + title | Ref. /chapter[1]/sect1[1]/title[1] |
| Original | Traduction | Introduction |
|
| + para | Ref. /chapter[1]/sect1[1]/para[1] |
| Original | Traduction |
Spring features integration classes for remoting support using various
technologies. The remoting support eases the development of remote-enabled
services, implemented by your usual (Spring) POJOs. Currently, Spring supports
four remoting technologies:
Remote Method Invocation (RMI). Through the use
of the RmiProxyFactoryBean and the
RmiServiceExporter Spring supports both traditional
RMI (with java.rmi.Remote interfaces and java.rmi.RemoteException) and
transparent remoting via RMI invokers (with any Java interface).
Spring's HTTP invoker. Spring provides a special
remoting strategy which allows for Java serialization via HTTP,
supporting any Java interface (just like the RMI invoker). The corresponding
support classes are HttpInvokerProxyFactoryBean and
HttpInvokerServiceExporter.
Hessian. By using the
HessianProxyFactoryBean
and the HessianServiceExporter you can transparently
expose your services using the lightweight binary HTTP-based protocol
provided by Caucho.
Burlap. Burlap is Caucho's XML-based
alternative for Hessian. Spring provides support classes such
as BurlapProxyFactoryBean and
BurlapServiceExporter.
JAX RPC (TODO).
JMS (TODO).
|
|
| + para | Ref. /chapter[1]/sect1[1]/para[2] |
| Original | Traduction |
While discussing the remoting capabilities of Spring, we'll use the following domain
model and corresponding services:
| + programlisting | Ref. /chapter[1]/sect1[1]/para[2]/programlisting[1] |
| Original | Traduction |
// Account domain object
public class Account implements Serializable{
private String name;
public String getName();
public void setName(String name) {
this.name = name;
}
}
|
|
| + programlisting | Ref. /chapter[1]/sect1[1]/para[2]/programlisting[2] |
| Original | Traduction |
// Account service
public interface AccountService {
public void insertAccount(Account acc);
public List getAccounts(String name);
}
|
|
| + programlisting | Ref. /chapter[1]/sect1[1]/para[2]/programlisting[3] |
| Original | Traduction |
// ... and corresponding implement doing nothing at the moment
public class AccountServiceImpl implements AccountService {
public void insertAccount(Account acc) {
// do something
}
public List getAccounts(String name) {
// do something
}
}
|
|
|
|
| + para | Ref. /chapter[1]/sect1[1]/para[3] |
| Original | Traduction |
We will start exposing the service to a remote client by using RMI and
talk a bit about the drawbacks of using RMI. We'll then continue to show
an example for Hessian.
|
|
| | sect1
| | + title | Ref. /chapter[1]/sect1[2]/title[1] |
| Original | Traduction | Exposing services using RMI |
|
| + para | Ref. /chapter[1]/sect1[2]/para[1] |
| Original | Traduction |
Using Spring's support for RMI, you can transparently expose your services through
the RMI infrastructure. After having this set up, you basically have a configuration
similar to remote EJBs, except for the fact that there is no standard support for
security context propagation or remote transaction propagation. Spring does provide
hooks for such additional invocation context when using the RMI invoker, so you can
for example plug in security frameworks or custom security credentials here.
|
| sect2
| | + title | Ref. /chapter[1]/sect1[2]/sect2[1]/title[1] |
| Original | Traduction | Exporting the service using the RmiServiceExporter |
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[1]/para[1] |
| Original | Traduction |
Using the RmiServiceExporter, we can expose the interface
of our AccountService object as RMI object. The interface can be accessed by using
RmiProxyFactoryBean, or via plain RMI in case of a traditional
RMI service. The RmiServiceExporter explicitly supports the
exposing of any non-RMI services via RMI invokers.
|
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[1]/para[2] |
| Original | Traduction |
Of course, we first have to set up our service in the Spring BeanFactory:
| + programlisting | Ref. /chapter[1]/sect1[2]/sect2[1]/para[2]/programlisting[1] |
| Original | Traduction |
<bean id="accountService" class="example.AccountServiceImpl">
<!-- any additional properties, maybe a DAO? -->
</bean>
|
|
|
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[1]/para[3] |
| Original | Traduction |
Next we'll have to expose our service using the RmiServiceExporter:
| + programlisting | Ref. /chapter[1]/sect1[2]/sect2[1]/para[3]/programlisting[1] |
| Original | Traduction |
<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
<!-- does not necessarily have to be the same name as the bean to be exported -->
<property name="serviceName"><value>AccountService</value></property>
<property name="service"><ref bean="accountService"/></property>
<property name="serviceInterface"><value>example.AccountService</value></property>
<!-- defaults to 1099 -->
<property name="registryPort"><value>1199</value></property>
</bean>
|
|
As you can see, we're overriding the port for the RMI registry. Often,
your application server also maintains an RMI registry and it is wise
to not interfere with that one.
Furthermore, the service name is used to bind the service under. So right now,
the service will be bound at rmi://HOST:1199/AccountService.
We'll use the URL later on to link in the service at the client side.
|
|
Note: We've left out one property, i.e. the servicePort
property, which is 0 by default. This means an anonymous port will be used
to communicate with the service. You can specify a different port if you like.
| | sect2
| | + title | Ref. /chapter[1]/sect1[2]/sect2[2]/title[1] |
| Original | Traduction | Linking in the service at the client |
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[2]/para[1] |
| Original | Traduction |
Our client is a simple object using the AccountService to manage accounts:
| + programlisting | Ref. /chapter[1]/sect1[2]/sect2[2]/para[1]/programlisting[1] |
| Original | Traduction |
public class SimpleObject {
private AccountService accountService;
public void setAccountService(AccountService accountService) {
this.accountService = accountService;
}
}
|
|
|
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[2]/para[2] |
| Original | Traduction |
To link in the service on the client, we'll create a separate bean factory,
containing the simple object and the service linking configuration bits:
| + programlisting | Ref. /chapter[1]/sect1[2]/sect2[2]/para[2]/programlisting[1] |
| Original | Traduction |
<bean class="example.SimpleObject">
<property name="accountService"><ref bean="accountService"/></bean>
</bean>
<bean id="accountService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl"><value>rmi://HOST:1199/AccountService</value></property>
<property name="serviceInterface"><value>example.AccountService</value></property>
</bean>
|
|
That's all we need to do to support the remote account service on the client.
Spring will transparently create an invoker and remotely enable the account
service through the RmiServiceExporter. At the client we're linking it in using
the RmiProxyFactoryBean.
|
|
| |
| | sect1
| | + title | Ref. /chapter[1]/sect1[3]/title[1] |
| Original | Traduction | Using Hessian or Burlap to remotely call services via HTTP |
|
| + para | Ref. /chapter[1]/sect1[3]/para[1] |
| Original | Traduction |
Hessian offers a binary HTTP-based remoting protocol. It's created by
Caucho and more information about Hessian itself can be found
at .
|
| sect2
| | + title | Ref. /chapter[1]/sect1[3]/sect2[1]/title[1] |
| Original | Traduction | Wiring up the DispatcherServlet for Hessian |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[1]/para[1] |
| Original | Traduction |
Hessian communicates via HTTP and does so using a custom servlet.
Using Spring's DispatcherServlet principles, you can easily
wire up such a servlet exposing your services. First we'll have to
create a new servlet in your application (this an excerpt from
web.xml):
| + programlisting | Ref. /chapter[1]/sect1[3]/sect2[1]/para[1]/programlisting[1] |
| Original | Traduction |
<servlet>
<servlet-name>remote</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
|
|
|
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[1]/para[2] |
| Original | Traduction |
You're probably familiar with Spring's DispatcherServlet principles and if so,
you know that know you'll have to create an application context named
remote-servlet.xml (after the name of your servlet) in
the WEB-INF directory. The application context will be used
in the next section.
|
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[3]/sect2[2]/title[1] |
| Original | Traduction | Exposing your beans by using the HessianServiceExporter |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[2]/para[1] |
| Original | Traduction |
In the newly created application context called remote-servlet.xml
we'll create a HessianServiceExporter exporting your services:
| + programlisting | Ref. /chapter[1]/sect1[3]/sect2[2]/para[1]/programlisting[1] |
| Original | Traduction |
<bean id="accountService" class="example.AccountServiceImpl">
<!-- any additional properties, maybe a DAO? -->
</bean>
<bean name="/AccountService" class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service"><ref bean="accountService"/></property>
<property name="serviceInterface">
<value>example.AccountService</value>
</property>
</bean>
|
|
Now we're ready to link in the service at the client. No handler mapping
is specified mapping requests (urls) onto services and that's why the BeanNameUrlHandlerMapping
will be used, hence the service will be exported at the URL http://HOST:8080/AccountService.
|
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[3]/sect2[3]/title[1] |
| Original | Traduction | Linking in the service on the client |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[3]/para[1] |
| Original | Traduction |
Using the HessianProxyFactoryBean we can link in the service
at the client. The same principles apply as with the RMI example. We'll create
a separate bean factory or application context and mention the following beans
where the SimpleObject is using the AccountService to manage accounts:
| + programlisting | Ref. /chapter[1]/sect1[3]/sect2[3]/para[1]/programlisting[1] |
| Original | Traduction |
<bean class="example.SimpleObject">
<property name="accountService"><ref bean="accountService"/></property>
</bean>
<bean id="accountService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<property name="serviceUrl"><value>http://remotehost:8080/AccountService</value></property>
<property name="ServiceInterface"><value>example.AccountService</value></property>
</bean>
|
|
That's all there is to it.
|
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[3]/sect2[4]/title[1] |
| Original | Traduction | Using Burlap |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[4]/para[1] |
| Original | Traduction |
We won't discuss Burlap, the XML-based equivalent of Hessian, in detail here,
since it is configured and set up in exactly the same way as the Hessian
variant explained above. Just replace the word Hessian
with Burlap and you're all set to go.
|
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[3]/sect2[5]/title[1] |
| Original | Traduction | Applying HTTP basic authentication to a service exposed through Hessian or Burlap |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[5]/para[1] |
| Original | Traduction |
One of the advantages of Hessian and Burlap is that we can easily apply HTTP basic
authentication, because both protocols are HTTP-based. Your normal HTTP server security
mechanism can easily be applied through using the web.xml security
features, for example. Usually, you don't use per-user security credentials here, but
rather shared credentials defined at the Hessian/BurlapProxyFactoryBean level
(similar to a JDBC DataSource).
|
|
| + programlisting | Ref. /chapter[1]/sect1[3]/sect2[5]/para[2]/programlisting[1] |
| Original | Traduction |
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="authorizationInterceptor"/>
</list>
</property>
</bean>
<bean id="authorizationInterceptor"
class="org.springframework.web.servlet.handler.UserRoleAuthorizationInterceptor">
<property name="authorizedRoles">
<list>
<value>administrator</value>
<value>operator</value>
</list>
</property>
</bean>
|
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[5]/para[3] |
| Original | Traduction |
This an example where we explicitly mention the BeanNameUrlHandlerMapping
and set an interceptor allowing only administrators and operators to call
the beans mentioned in this application context.
|
|
Note: Of course, this example doesn't show a flexible kind of security
infrastructure. For more options as far as security is concerned,
have a look at the Acegi Security System for Spring, to be found at
.
| |
| | sect1
| | + title | Ref. /chapter[1]/sect1[4]/title[1] |
| Original | Traduction | Exposing services using HTTP invokers |
|
| + para | Ref. /chapter[1]/sect1[4]/para[1] |
| Original | Traduction |
As opposed to Burlap and Hessian, which are both lightweight protocols using their
own slim serialization mechanisms, Spring Http invokers use the standard
Java serialization mechanism to expose services through HTTP. This has a huge
advantage if your arguments and return types are complex types that cannot be
serialized using the serialization mechanisms Hessian and Burlap use (refer to the
next section for more considerations when choosing a remoting technology).
|
|
| + para | Ref. /chapter[1]/sect1[4]/para[2] |
| Original | Traduction |
Under the hood, Spring uses either the standard facilities provided by J2SE to
perform HTTP calls or Commons HttpClient. Use the latter if you need more advanced
and easy-to-use functionality. Refer to
jakarta.apache.org/commons/httpclient
for more info.
|
| sect2
| | + title | Ref. /chapter[1]/sect1[4]/sect2[1]/title[1] |
| Original | Traduction | Exposing the service object |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[1]/para[1] |
| Original | Traduction |
Setting up the HTTP invoker infrastructure for a service objects much resembles
the way you would do using Hessian or Burlap. Just as Hessian support provides
the HessianServiceExporter, Spring Http invoker support provides
the so-called org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter.
To expose the AccountService (mentioned above), the following
configuration needs to be in place:
| + programlisting | Ref. /chapter[1]/sect1[4]/sect2[1]/para[1]/programlisting[1] |
| Original | Traduction |
<bean name="/AccountService" class="org.sprfr.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="service"><ref bean="accountService"/></property>
<property name="serviceInterface">
<value>example.AccountService</value>
</property>
</bean>
|
|
|
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[4]/sect2[2]/title[1] |
| Original | Traduction | Linking in the service at the client |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[2]/para[1] |
| Original | Traduction |
Again, linking in the service from the client much resembles the way you would
do it when using Hessian or Burlap. Using a proxy, Spring will be able to
translate your calls to HTTP POST requests to the URL pointing to the exported
service.
| + programlisting | Ref. /chapter[1]/sect1[4]/sect2[2]/para[1]/programlisting[1] |
| Original | Traduction |
<bean id="httpInvokerProxy" class="org.sprfr.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl">
<value>http://remotehost:8080/AccountService</value>
</property>
<property name="serviceInterface">
<value>example.AccountService</value>
</property>
</bean>
|
|
|
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[2]/para[2] |
| Original | Traduction |
As mentioned before, you can choose what HTTP client you want to use.
By default, the HttpInvokerProxy uses the J2SE HTTP functionality, but
you can also use the Commons HttpClient by setting the httpInvokerRequestExecutor property:
| + programlisting | Ref. /chapter[1]/sect1[4]/sect2[2]/para[2]/programlisting[1] |
| Original | Traduction |
<property name="httpInvokerRequestExecutor">
<bean class="org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor"/>
</property>
|
|
|
|
| |
| | sect1
| | + title | Ref. /chapter[1]/sect1[5]/title[1] |
| Original | Traduction | Considerations when choosing a technology |
|
| + para | Ref. /chapter[1]/sect1[5]/para[1] |
| Original | Traduction |
Each and every technology presented here has its drawbacks. You should carefully
consider you needs, the services your exposing and the objects you'll be sending
over the wire when choosing a technology.
|
|
| + para | Ref. /chapter[1]/sect1[5]/para[2] |
| Original | Traduction |
When using RMI, it's not possible to access the objects through the HTTP protocol,
unless you're tunneling the RMI traffic. RMI is a fairly heavy-weight protocol
in that it support full-object serialization which is important when using a
complex data model that needs serialization over the wire. However, RMI-JRMP
is tied to Java clients: It is a Java-to-Java remoting solution.
|
|
| + para | Ref. /chapter[1]/sect1[5]/para[3] |
| Original | Traduction |
Spring's HTTP invoker is a good choice if you need HTTP-based remoting but also
rely on Java serialization. It shares the basic infrastructure with RMI invokers,
just using HTTP as transport. Note that HTTP invokers are not only limited to
Java-to-Java remoting but also to Spring on both the client and server side.
(The latter also applies to Spring's RMI invoker for non-RMI interfaces.)
|
|
| + para | Ref. /chapter[1]/sect1[5]/para[4] |
| Original | Traduction |
Hessian and/or Burlap might provide significant value when operating in a
heterogeneous environment, because they explicitly allow for non-Java clients.
However, non-Java support is still limited. Known problems include the serialization
of Hibernate objects in combination with lazily initializing collections. If you
have such a data model, consider using RMI or HTTP invokers instead of Hessian.
|
|
| + para | Ref. /chapter[1]/sect1[5]/para[5] |
| Original | Traduction |
JMS can be useful for providing clusters of services and allowing the JMS broker
to take care of load balancing, discovery and auto-failover.
By default Java serialization is used when using JMS remoting but
the JMS provider could use a different mechanism for the wire formatting,
such as XStream to allow servers to be implemented in other technologies.
|
|
| + para | Ref. /chapter[1]/sect1[5]/para[6] |
| Original | Traduction |
Last but not least, EJB has an advantage over RMI in that it supports standard
role-based authentication and authorization and remote transaction propagation.
It is possible to get RMI invokers or HTTP invokers to support security context
propagation as well, although this is not provided by core Spring: There are
just appropriate hooks for plugging in third-party or custom solutions here.
|
|
| |
|