Spring学习 HTTP Invoker

Spring HTTP Invoker一种JAVA远程方法调用框架实现,原理与JDK的RMI基本一致,所以我们先跟其它JAVA远程方法调用实现做下简单比较。

  • RMI:使用JRMP协议(基于TCP/IP),不允许穿透防火墙,使用JAVA系列化方式,使用于任何JAVA应用之间相互调用。

  • Hessian:使用HTTP协议,允许穿透防火墙,使用自己的系列化方式,支持JAVA、C++、.Net等跨语言使用。

  • Burlap: 与Hessian相同,只是Hessian使用二进制传输,而Burlap使用XML格式传输(两个产品均属于caucho公司的开源产品)。

  • Spring HTTP Invoker: 使用HTTP协议,允许穿透防火墙,使用JAVA系列化方式,但仅限于Spring应用之间使用,即调用者与被调用者都必须是使用Spring框架的应用。


为什么使用Spring HTTP Invoker?我们可以看下Spring源码中的注释说明:

1
2
3
4
5
/* <p><b>HTTP invoker is the recommended protocol for Java-to-Java remoting.</b>
* It is more powerful and more extensible than Hessian and Burlap, at the
* expense of being tied to Java. Nevertheless, it is as easy to set up as
* Hessian and Burlap, which is its main advantage compared to RMI.
*/

Spring一定希望大家尽量使用它的产品,但实际项目中我们还是要根据需求来决定选择哪个框架,下面我们来看看Spring HTTP Invoker的使用。

代码结构图如下:

客户端通过Spring的HttpInvoker,完成对远程函数的调用。涉及的类有:

客户端调用User类的服务UserService,完成对实现类UserServiceImpl的addUser(User u)方法调用。其中User类为普通Pojo对象,UserService为接口,UserServiceImpl为UserService的具体实现。代码如下:
public interface UserService {
    void addUser(User u);
}

public class UserServiceImpl implements UserService {
    public void addUser(User u) {
        System.out.println(“add user ["+u.getUsername()+ "] ok !!!”);
    }
}

客户端调用时,主方法代码为:
public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
                new String[] {“ApplicationContext.xml” });
    
        UserService us = (UserService)ctx.getBean(“ServletProxy”);
        us.addUser(new User(“Hook1″));
        
        UserService us2 = (UserService)ctx.getBean(“UrlPathProxy”);
        us2.addUser(new User(“Hook2″));
    }

其调用流程用时序图可表示为:

图中粉红色表示基于Url映射方式的配置时程序的处理流程,红色表示基于Servlet配置时的处理流程。
当以示基于Url映射方式的配置时,远程系统处理请求的方式同SpringMVC的controller类似,所有的请求通过在web.xml中的org.springframework.web.servlet.DispatcherServlet统一处理,根据url映射,去对应的【servlet名称-servlet.xml】文件中,查询跟请求的url匹配的bean配置;而基于Servlet配置时,由org.springframework.web.context.support.HttpRequestHandlerServlet去拦截url-pattern匹配的请求,如果匹配成功,去ApplicationContext中查找name与servlet-name一致的bean,完成远程方法调用。

当使用URL映射配置时,实力配置如下(application-servlet.xml):
<bean name=”/userHttpInvokerService” class=”org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter”>
        <property name=”service” ref=”userService”/>
        <property name=”serviceInterface” value=”com.handou.httpinvoker.service.UserService”/>
    </bean>

web.xml文件配置:
 <servlet>
        <servlet-name>application</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
     
    <servlet-mapping>
        <servlet-name>application</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

 如果使用基于Servlet的配置,web.xml文件配置如下:

    <!– 基于servlet配置时使用 ,根据请求的url匹配url-pattern,如果匹配成功,去ApplicationContext
    中查找name与servlet-name一致的bean–>
    <servlet>
        <servlet-name>userHttpInvokerService</servlet-name>
        <servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>userHttpInvokerService</servlet-name>
        <url-pattern>/UserHttpInvokerService</url-pattern>
    </servlet-mapping>

applicationContext.xml文件中配置如下:
<bean id=”userService” class=”com.handou.httpinvoker.service.UserServiceImpl” />
    <!–第二种配置方式 –> 
    <bean name=”userHttpInvokerService” 
        class=”org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter”>
        <property name=”service” ref=”userService”/>
        <property name=”serviceInterface” value=”com.handou.httpinvoker.service.UserService”/>
    </bean>

两种方式,客户端配置均相同:
<bean id=”ServletProxy” 
     class=”org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean”>  
     <property name=”serviceUrl”>  
           <value>http://localhost:8080/HttpInvoke/UserHttpInvokerService</value>  
       </property>  
       <property name=”serviceInterface”>  
            <value>com.handou.httpinvoker.service.UserService</value>  
        </property>  
   </bean>

具体可参考源码 :点击下载

==========================================================================================================================

Spring HTTP Invoker是spring框架中的一个远程调用模型,执行基于HTTP的远程调用,也就是说,可以通过防火墙,并使用java的序列化机制在网络间传递对象。客户端可以很轻松的像调用本地对象一样调用远程服务器上的对象,要注意的一点是,服务端、客户端都是使用Spring框架。下面通过一个例子,来 讲解Spring HTTP Invoker的使用,这里使用的是 Spring2.5.6 框架 
Spring HTTP Invoker的整体流程如下 (下图显示整个调用的过程) 

  1. 客户端
    1. 向服务器发送远程调用请求
      远程调用信息-->封装为远程调用对象-->序列化写入到远程调用http请求中-->向服务器端发送
    2. 接收服务器端返回的远程调用结果
      服务器端返回的远程调用结果HTTP响应——>反序列化为远程调用结果对象
  2. 服务端
    1. 接收客户端发送的远程调用请求
      客户端发送的远程调用HTTP请求——>反序列化为远程调用对象——>调用服务器端目标对象的目标方法处理
    2. 向客户端返回远程调用结果
      服务器端目标对象方法的处理结果——>序列化写入远程调用结果HTTP响应中——>返回给客户端。


Spring HTTP Invoker有两种实现方式  
  1.  基于Url映射方式,远程系统处理请求的方式同SpringMVC的controller类似,所有的请求通过在web.xml中的 org.springframework.web.servlet.DispatcherServlet统一处理,根据url映射,去对应的 【servlet名称-servlet.xml】文件中,查询跟请求的url匹配的bean配置
  2. 基于Servlet方式,由org.springframework.web.context.support.HttpRequestHandlerServlet去拦截url- pattern匹配的请求,如果匹配成功,去ApplicationContext中查找name与servlet-name一致的bean,完成远程方法调用。
这里采用第一种方式进行实现。先配置服务端  
  1. 建立web项目
  2. 导入jar包
    1. spring.jar
    2. spring-webmvc.jar
    3. commons-logging-1.1.2.jar
  3. 在web.xml新增如下配置文件
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    < servlet >
             < servlet-name >application</ servlet-name >
             < servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class >
             < load-on-startup >1</ load-on-startup >
         </ servlet >
          
         < servlet-mapping >
             < servlet-name >application</ servlet-name >
             < url-pattern >/*</ url-pattern >
    </ servlet-mapping >

  4. WEB-INF下增加application-servlet.xml (注意xml文件的命名,这里的application要和servlet-name名字保持一致)配置如下
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <? xml version = "1.0" encoding = "UTF-8" ?>
    <! DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
    "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
    < beans >
         < bean id = "userService" class = "org.felix.service.impl.UserServiceImpl" />
         <!-- 基于Url映射方式,这个配置,就是把userService接口,提供给远程调用 -->
         < bean id = "httpService"  class = "org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter" >
             < property name = "service" ref = "userService" />
             < property name = "serviceInterface" value = "org.felix.service.UserService" />
         </ bean >
         <!-- 远程服务的URL -->
         < bean
             class = "org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" >
              < property name = "mappings" >
                 < props >
                       < prop key = "/test" >httpService</ prop >
                 </ props >
             </ property >
         </ bean >
    </ beans >

  5. 建立相关类和包结构,如下图所示

  6. 各类代码如下
    User类,需要实现Serializable 接口
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    package org.felix.model;
     
    import java.io.Serializable;
     
    public class User implements Serializable {
         
         /**
          *
          */
         private static final long serialVersionUID = 1L;
         private String name;
         private String password;
         public String getName() {
             return name;
         }
         public void setName(String name) {
             this .name = name;
         }
         public String getPassword() {
             return password;
         }
         public void setPassword(String password) {
             this .password = password;
         }
         
    }
    UserService接口
    ?
    1
    2
    3
    4
    5
    6
    7
    package org.felix.service;
     
    import org.felix.model.User;
     
    public interface UserService {
         void add(User u);
    }
    UserService接口的实现类UserServiceImpl
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package org.felix.service.impl;
     
    import org.felix.model.User;
    import org.felix.service.UserService;
     
    public class UserServiceImpl implements UserService {
     
         @Override
         public void add(User u) {
             System.out.println( "add user[" + u.getName() + "]" );
         }
     
    }

配置客户端  
  1.  复制服务端工程,重命名一下,工程结构如下图

  2. src目录下新建application-servlet.xml配置如下
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <? xml version = "1.0" encoding = "UTF-8" ?>
    <! DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
    "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
    < beans >
         < bean id = "httpTestService"
         class = "org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean" >
             < property name = "serviceUrl" >
                 < value >http://localhost:8080/felix_0400_SpringHttp_Server/test</ value >
             </ property >
             < property name = "serviceInterface" >
                 < value >org.felix.service.UserService</ value >
             </ property >
         </ bean >
    </ beans >
  3. 新建测试类TestSpringHttp代码如下
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    import org.felix.model.User;
    import org.felix.service.UserService;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
     
     
    public class TestSpringHttp {
         private static ApplicationContext context = new ClassPathXmlApplicationContext( "application-servlet.xml" );
         
         public static UserService getUserService(){
             return (UserService)context.getBean( "httpTestService" );
         }
         public static void main(String[] args) {
             User user = new User();
             user.setName( "felix" );
             user.setPassword( "felix" );
             getUserService().add(user);
         }
    }

  4. 运行程序在控制台输出如下

参考文章

  1. Spring中HttpInvoker远程调用使用实例

  2. Spring HTTP Invoker例子

  3. 《Spring技术内幕》学习笔记17——Spring HTTP调用器实现远程调用



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值