javaspringspring-mvcspring-remoting

spring remoting mapping urls


I've followed the tutorial for spring remoting, in particular HttpInvokerServiceExporter and have no problems setting up both the client and the server (factorybean).

Question is, I've noticed using Spring MVC, each interface is mapped to a particular URL

<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="hello.htm">test_service</prop>
            </props>
        </property>
    </bean>

    <!-- *********************exposed web services*************************--> 
    <bean name="test_service" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
        <property name="serviceInterface" value="foo.webservices.HelloServiceInterface" />
        <property name="service">
            <ref bean="helloService"></ref>
        </property>

Question is, if I have more than 1 method in my service interface, is it possible to map each of these interface methods to a URL themselves?


Solution

  • The idea behind HTTPInvokerServiceExporter is to provide an endpoint to receive remove method invocation.

    On the server side it would be easy as configure a RemoteExporter, declaring the interface you want to expose and associating it to the real bean that will handle the invocations.

    On the client it would be necessary configure the RemoteAcessor that basically needs the interface that is going be access on the server side.

    The implementation over HTTP can be done using HttpInvokerServiceExporter on the server side like the following example:

    Service Interface:


    package foo.bar.services;
    
    public interface MyService {
    
        public int sum(int num1, int num2);
    
    }
    

    For this service you would have an implementation (let's say foo.bar.services.DefaultMyService).

    The exposition and configuration on spring context would look like:


    <bean name="myService" class="foo.bar.DefaultMyService" />
    <bean name="/myService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
      <property name="service" ref="myService"/>
      <property name="serviceInterface" value="foo.bar.MyService"/>
    </bean>
    

    With this configuration I just intended to have a instance of my implementation of MyService being exposed under foo.bar.MyService interface over the URL mapped by /myService (bean name) in the simpliest case using BeanNameUrlHandlerMapping that does nothing else than map a URL to a bean with the URL value (this case /myService).

    On the client side (consumer), you will have a bean configured just declaring the interface you expect the remote side is exposing. For our service would be something like:

    <bean id="httpInvokerProxy" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
      <property name="serviceUrl" value="http://foo.bar.org/springSample/myService"/>
      <property name="serviceInterface" value="foo.bar.MyService"/>
    </bean>
    

    At the moment spring instantiate the beans on client side, a proxy is instantiated and every method invocation would then be serialized and sent over HTTP to the endpoint (in this case http://foo.bar.org/springSample/myService. At the server side this request is deserialized and interpreted i.e. invoking the method on the real service being exposed (on our case DefaultMyService). The service will return something that will be serialized an gave as result to the HTTP request performed by the client. The client will receive it and deserialize it and return it to the original method invocator.

    As you can see (and got from Spring documentation):

    The server side will

    Deserializes remote invocation objects and serializes remote invocation result objects. Uses Java serialization just like RMI, but provides the same ease of setup as Caucho's HTTP-based Hessian and Burlap protocols.

    The client side will

    Serializes remote invocation objects and deserializes remote invocation result objects. Uses Java serialization just like RMI, but provides the same ease of setup as Caucho's HTTP-based Hessian and Burlap protocols.

    The serialization used with Spring Remoting on this case is Java serialization, meaning the HTTP request holds an entity body containing the serialized object (is good to keep in mind that in this case JVM version and class versions needs to be compatible).

    The exposition is done as a whole, you could not separate it having one URL for each method of that interface. Therefore would be easier the use of Spring MVC and create a controller (@Controller) implement a method for each method you have on your interface annotating it as @RequestMapping (with the desired URL) and invoke the method on the service as follows the example:

    Controller Sample


    package foo.bar;
    
    import foo.bar.service.MyService;
    
    @Controller
    public class MyService {
        @Autowired
        private MyService myService;
    
        @RequestMapping("/sum/{num1}/{num2}")
        public int sum(@PathVariable("num1") int num1, @PathVariable("num2") int num2) {
            return myService.sum(num1, num2);
        }
    
    }
    

    Using the context configuration

    <context:component-scan base-package="foo.bar"/>
    

    it would map the classes found on foo.bar and under packages automatically, meaning the Service implementation (DefaultMyService) could be mapped with @Service and @Autowired to the controller as done in the sample, without any bean configuration on the context xml.

    But this will expose your service over REST interface, meaning it will handle HTTP plain requests that could be done by other consumers like a PHP consumer (this couldn't be done with Spring Remoting because it uses pure Java serialization).

    If your client is Java you could definitively use Remoting and expose your service as a whole, if not the REST implementation using Spring MVC is a good solution.

    Spring Documentation can be found here