Spring-use and comparison of several RPC models

Source: Internet
Author: User

In spring, using JMS for RPC uses:

    • Org.springframework.jms.remoting.JmsInvokerServiceExporter
    • Org.springframework.jms.remoting.JmsInvokerProxyFactoryBean


Spring provides consistent style support in several ways of implementing RPC.
Here I'm going to record several RPC models and compare them.

    • Rmi
    • Hessian/burlap
    • HTTP Invoker
    • JAX-ws

Rmi


Start with the most basic RMI first.
RMI-related APIs are available as early as JDK1.1, and here I briefly describe the native implementation of RMI (the code can be referenced elsewhere).

    • Declares a remote interface, the interface must inherit java.rmi.Remote, the method needs to throw java.rmi.RemoteException.
    • Provides implementations for remote interfaces that implement classes that need to inherit unicastremoteobject.
    • Or you can use RMI-related commands to create Skelton and stubs.
    • Start an RMI registry and register.


If spring implements RMI, the method is much simpler.
We only need to use two classes:

    • Org.springframework.remoting.rmi.RmiServiceExporter
    • Org.springframework.remoting.rmi.RmiProxyFactoryBean


I'll simply define the interface and implementation classes:

package pac.testcase.ws;public interface MyService {    public boolean inviteMeIn();    public String welcome();}

package pac.testcase.ws.impl;import pac.testcase.ws.MyService;public class MyServiceImpl implements MyService{    public boolean inviteMeIn() {        return true;    }    public String welcome() {        return "Everybody is welcome!!";    }}


Simple, no need to inherit anything else, very pojo.

The following are the spring-related configurations:

<bean id="myService" class="pac.testcase.ws.impl.MyServiceImpl" /><bean class="org.springframework.remoting.rmi.RmiServiceExporter"    p:service-ref="myService"    p:serviceName="welcomeService"    p:serviceInterface="pac.testcase.ws.MyService"/>


Export our Pojo as RMI service, where I use the default configuration.
The address is as follows by default:

/** * Set the host of the registry for the exported RMI service, * i.e. {@code rmi://HOST:port/name} * <p>Default is localhost. */public void setRegistryHost(String registryHost) {    this.registryHost = registryHost;}/** * Set the port of the registry for the exported RMI service, * i.e. {@code rmi://host:PORT/name} * <p>Default is {@code Registry.REGISTRY_PORT} (1099). * @see java.rmi.registry.Registry#REGISTRY_PORT */public void setRegistryPort(int registryPort) {    this.registryPort = registryPort;}


The client side uses Rmiproxyfactorybean, and the proxy service is like a simple bean:

<bean id="clientSideService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean"    p:serviceUrl="rmi://localhost:1099/welcomeService"    p:serviceInterface="pac.test.RemoteService"/>


The Pac.test.RemoteService in the configuration is the simple bean that is redefined here, depending on the needs of the client.

package pac.test;public interface RemoteService {    public String welcome();}


This makes it possible to invoke on the server, without doing anything naming.lookup (serviceurl), and the remote call becomes transparent.

ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");RemoteService service = (RemoteService)context.getBean("clientSideService");System.out.println(service.welcome());



RMI is simple and efficient, but there are some problems with RMI, such as a version of Java serialization or a firewall problem (RMI is not HTTP-based).

Hessian/burlap


Hessian and Burlap, now in Caucho's website are almost invisible to this aspect of the content.
I don't know if anyone else will use these two things, although last year out of a version, but the previous version was in 2010 years.
Asked in the group just now there is no one to use, the result is really someone with Hessian, they are C # and Java to do communication.
Burlap performance is more troublesome, I do not know if anyone mentioned.
Although I do not know how to use the situation, but also here a simple record, expand the thinking.


Hessian and burlap are provided by Caucho, and Hessian is part of the resin.
These two things are like two parts of the same thing, like a gun and a chainsaw?


Hessian is binary transport protocol, but unlike RMI, he is not a Java serialization object, so he can communicate with programs in other languages, such as C + +, C #, Python, Ruby, etc.
Burlap is XML-based and can naturally support many different languages.
Of course, the same transfer of content, the amount of XML will be larger.
If there are any good things to say, it's only readable.


It's too lazy to add dependencies and provide native implementations, but he's not complicated.

Creating a Hessian service using Java have four steps:

    • Create a Java interface as the public API
    • Create a client using hessianproxyfactory
    • Create the Service implementation class
    • Configure the service in your servlet engine.


Here I am primarily documenting how to export and invoke the Hessian service in spring.
As stated above, I need to configure the service to the servlet engine;
Both the server and the client need to add a dependency:

<dependency>    <groupId>com.caucho</groupId>    <artifactId>hessian</artifactId>    <version>4.0.33</version></dependency>


Just as I have an application using SPRINGMVC, I'm going to export the Hessian service on this basis.

<servlet>    <servlet-name>springServlet</servlet-name>    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>    <init-param>        <param-name>contextConfigLocation</param-name>        <param-value>/WEB-INF/spring-mvc.xml</param-value>    </init-param>    <load-on-startup>1</load-on-startup></servlet><servlet-mapping>    <servlet-name>springServlet</servlet-name>    <url-pattern>/</url-pattern></servlet-mapping>

Simply write an interface and implement:

package pac.king.common.rpc;public interface MyHessianService {    public String justHadEnoughParties();}

package pac.king.common.rpc.impl;import pac.king.common.rpc.MyHessianService;public class MyHessianServiceImpl implements MyHessianService {    public String justHadEnoughParties() {        return "Please save me..";    }}


I have made the following configuration in Spring-mvc.xml and used requestmapping annotations in *controller to map the URLs.
But that doesn't prevent me from exporting the Hessian service and mapping a URL for it:

<context:component-scan base-package="pac.king.controller"    use-default-filters="false">    <context:include-filter type="annotation"        expression="org.springframework.stereotype.Controller" /></context:component-scan><bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">    <property name="mappings">        <value>            /service=myHessianService        </value>    </property></bean>


Export Hessian Service:

<bean id="myHessianServiceImpl" class="pac.king.common.rpc.impl.MyHessianServiceImpl" /><bean id="myHessianService" class="org.springframework.remoting.caucho.HessianServiceExporter"    p:service-ref="myHessianServiceImpl"    p:serviceInterface="pac.king.common.rpc.MyHessianService"/>


Now that it can be called, I need to declare an interface (Pac.test.HessianService) on the client and then invoke it with the proxy:

<bean id="myHessianClient" class="org.springframework.remoting.caucho.HessianProxyFactoryBean"    p:serviceUrl="http://localhost:8080/runtrain/service"    p:serviceInterface="pac.test.HessianService"/>


Call:

ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");HessianService service = (HessianService)context.getBean("myHessianClient");System.out.println(service.justHadEnoughParties());


Console output:

For burlap, there is almost no difference from the configuration of Hessian;
Only need to change hessianserviceexporter to Burlapserviceexporter,
and change the Hessianproxyfactorybean to Burlapproxyfactorybean.

RMI uses the serialization of Java, while Hessian/burlap uses private serialization for communication between different languages.
If I need HTTP-based, but I don't need multi-language support, I just want to use Java ...

Httpinvoker


Should I say this is an HTTP-based RMI?
Although it seems to have the most of both worlds, there are places where people are "sorry",
(In fact, I did not regret to say that I have done a project without spring, even the persistence layer framework is self-fulfilling, the longer the more painful ...)
He does not have the so-called "native" implementation, which is part of spring and can only be used in spring applications.


The related classes provided by spring for these RPC communication models have the same name:

    • Service side: *serviceexporter
    • Client: *proxyfactorybean


Naturally, the Httpinvoker will use

    • Org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter
    • Org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean


Httpinvoker-based services are distributed by Dispatcherservlet as well as Hessian.
Given many of the same places, I intend to continue using the interface and implementation classes in the previous article with Hessian communication.

I hardly ever have to do any work, and the URL mapping does not need to be modified, I just need to modify the server configuration:

<bean id="myHessianServiceImpl" class="pac.king.common.rpc.impl.MyHessianServiceImpl" /><!-- <bean id="myHessianService" class="org.springframework.remoting.caucho.HessianServiceExporter"    p:service-ref="myHessianServiceImpl"    p:serviceInterface="pac.king.common.rpc.MyHessianService"/> --><bean id="myHessianService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter"    p:service-ref="myHessianServiceImpl"    p:serviceInterface="pac.king.common.rpc.MyHessianService"/>


Accordingly, the client only needs to modify the class:

<!-- <bean id="myHessianClient" class="org.springframework.remoting.caucho.HessianProxyFactoryBean"    p:serviceUrl="http://localhost:8080/runtrain/service"    p:serviceInterface="pac.test.HessianService"/> --><bean id="myHessianClient" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean"    p:serviceUrl="http://localhost:8080/runtrain/service"    p:serviceInterface="pac.test.HessianService"/>


This ensures efficiency and solves the firewall problem.
Later I heard someone say that when they use Hessian for cross-language communication, the HTTP-based feature does not solve the firewall problem.
I don't know what they are, but they don't seem to be talking about it.


After watching the Hessian, I suddenly felt that the Web service was so cumbersome (although there are some ways to overcome some of the problems).
Now that you have Hessian, why do you use Web service?
I suddenly began to doubt the meaning of his existence.
Search, the results are compared to the efficiency of the RPC communication model, no one said why they have to use (should have the meaning of the existence of it) ...
If it's just efficiency, you can use Hessian.
With this question I stroll around the StackOverflow, and then I get the following several answers.

    • When most people hold a hammer in their hands, they tend to treat all problems as nails, and they usually don't try to find another tool. This is why the Web service is flooding.
    • I think you should take a look at the advantages of Web service (the result is that people say cross-language and SOA ...) is the key or relative to what do compare ...)
    • Are WEB service slow to communicate with those non-xml? This relative speed problem is more dependent on the business requirements and your own code implementations (this same argument applies to reflection).


In the end, I still did not get the answer that I satisfied, but review the Web service ...
In many similar scenarios, people see Web service as "standard" option. Case... Let's look at the Web service.

JAX-ws


It seems that the use of Web service is unavoidable.
I had a little resistance to this, because he gave me the impression of always trouble + slow (later, although a lot of convenience, but still very slow).
Then search for "Advantages of Web Service" and try to accept him again.
Simply record how to export endpoint with spring.

Suppose I want to have a spring application, I need to export a pojo or part of the method as a Web Service.
But there's a problem. The life cycle of--endpoint is managed by Jax-WS runtime (the lifecycle of such an endpoint instance'll be managed by the Jax-ws Runtim e),
The beans in spring context cannot be autowire to endpoint, and those I want to export use spring-managed beans.


For this, we have two workarounds:

    • Org.springframework.web.context.support.SpringBeanAutowiringSupport
    • Jaxwsserviceexporter


The paragraph in the brackets above me is a reference to the springbeanautowiringsupport Javadoc.
The typical case for using this class is that the bean is injected into the JAX-WS endpoint Class (which is written in the comments) and can be used by any scenario where the life cycle is not managed by spring.
And we just have to inherit this class, which means that when we create an instance, we call the parent class's parameterless constructor, and we look at how he constructs it:

/** * This constructor performs injection in this instance, * based in the current Web application context. * <p>intended for use as a base class.    * @see #processInjectionBasedOnCurrentContext */public springbeanautowiringsupport () { Processinjectionbasedoncurrentcontext (this);} /** * Process {@code @Autowired} injection for the given target object, * based in the current Web application context. * <p>intended for use as a delegate. * @param target the target object to process * @see org.springframework.web.context.contextloader#    Getcurrentwebapplicationcontext () */public static void Processinjectionbasedoncurrentcontext (Object target) {    Assert.notnull (target, "target object must not is null");    Webapplicationcontext cc = Contextloader.getcurrentwebapplicationcontext ();        if (cc! = null) {autowiredannotationbeanpostprocessor BPP = new Autowiredannotationbeanpostprocessor ();        Bpp.setbeanfactory (Cc.getautowirecapablebeanfactory ()); Bpp.processinjection (target); } else {if (logger.isdebugenabled ()) {Logger.debug ("current webapplicationcontext are not available  For processing of "+ Classutils.getshortname (Target.getclass ()) +": "+" make sure This class gets constructed in a Spring Web application. Proceeding without injection. ");}}


Then try it:

@Service@WebService(serviceName="testMyService")public class MyServiceEndpoint extends SpringBeanAutowiringSupport{    @Autowired    MyService myService;    @WebMethod    public String sayHiFarAway(String name){        return myService.sayHiTo(name);    }}

Then publish it:

ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:applicationContext*.xml");Endpoint.publish("http://localhost:8080/myservices", (MyServiceEndpoint)context.getBean(MyServiceEndpoint.class));


Call:

javax.xml.ws.Service service = javax.xml.ws.Service.create(url, new QName("http://endpoint.king.pac/","testMyService"));QName q = new QName("http://endpoint.king.pac/","MyServiceEndpointPort");MyClientService client = service.getPort(q,MyClientService.class);System.out.println(client.sayHiFarAway("King"));


Write a endpoint also to inherit and business-independent classes, make people uncomfortable ... And it's cumbersome to publish and call.
Try simplejaxwsserviceexporter, you can export a endpoint simply by configuring it.
But he also has a point to note, citing the Javadoc of the class:

Note that this exporter would only work if the JAX-WS runtime actually supports publishing with an address argument, i.e. I f the Jax-WS runtime ships an internal HTTP server. The the case with the Jax-WS runtime that's inclued in Sun's JDK 1.6 but not with the standalone Jax-WS 2.1 RI.


Simplejaxwsserviceexporter automatically detect all classes that are WebService annotated, so you only need to declare them in the configuration, at which point the endpoint address uses the default localhost:8080 directly:

<bean class="org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter" />


Then improve the client call, using Jaxwsportproxyfactorybean:

<bean id="clientSide" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean"    p:wsdlDocumentUrl="http://localhost:8080/testMyService?wsdl"    p:serviceName="testMyService"    p:portName="MyServiceEndpointPort"    p:serviceInterface="pac.king.endpoint.MyClientService"    p:namespaceUri="http://endpoint.king.pac/"/>


This allows you to use the service as you would with a normal bean:

MyClientService client = (MyClientService)context.getBean("clientSide");System.out.println(client.sayHiFarAway("King"));


It's a lot easier to use, but it still can't change a fact:

WEB Service Requests is larger than requests encoded with a binary protocol.

There is also the problem of Http/https.
If used improperly, I may need to do more work to deal with things that HTTP does not do, and RMI is a great fit.

Spring-use and comparison of several RPC models

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.