Spring HTTP invoker简介

Spring HTTP invoker是spring框架中的一个远程调用模型,执行基于HTTP的远程调用(意味着可以通过防火墙),并使用java的序列化机制在网络间传递对象。客户端可以很轻松的像调用本地对象一样调用远程服务器上的对象,这有点类似于webservice,但又不同于webservice,区别如下:

webservice

HTTP invoker

跨平台,跨语言

只支持java语言

支持SOAP,提供wsdl

不支持

结构庞大,依赖特定的webservice实现,如xfire等

结构简单,只依赖于spring框架本身

项目中使用哪种远程调用机制取决于项目本身的要求。

HttpInvoker服务模式

说明:

1.  服务器端:通过HTTP invoker服务将服务接口的某个实现类提供为远程服务

2.  客户端:通过HTTP invoker代理向服务器端发送请求,远程调用服务接口的方法

3.  服务器端与客户端通信的数据需要序列化

配置服务器端和客户端的步骤

配置服务器端

1.  添加springJAR文件

  建议使用spring2+.jar版本

2.  创建服务接口

3.  创建服务接口的具体实现类

4.  公开服务

配置客户端

1.  添加springJAR文件

  建议使用spring2+.jar版本

2.  创建服务接口

3.  访问服务

实例讲解

服务器端

1.服务接口:UcService.java

它提供两项服务,查询用户信息和记录日志,如下:

public interface UcService {
public UserInfo getUserInfobyName(String userName);
public int recordLog(String username, String point, String operate, String desc);
}

说明:举这个列子是因为其比较有代表性,它将展示普通数据类型(int,long等)和复杂数据类型(DTO等)的远程调用方式。UserInfo是一个普通的DTO,代码如下:

public class UserInfo implements Serializable {
private static final long serialVersionUID = -6970967506712260305L; /** 用户名 */
private String userName ; /** 电子邮箱 */
private String email ; /** 注册日期 */
private Date registDate ; public String getUserName() {
return userName ;
} public void setUserName(String userName) {
this . userName = userName;
} public String getEmail() {
return email ;
} public void setEmail(String email) {
this . email = email;
} public Date getRegistDate() {
return registDate ;
} public void setRegistDate(Date registDate) {
this . registDate = registDate;
}
}

注意:因为是在网络间传输对象,所以需要将UserInfo实现Serializable接口,并指定一个serialVersionUID(任意值即可,同时客户端也要有这个类,否则在客户端接收对象时会因为serialVersionUID不匹配而出现异常)

回到UcService.java,它提供了两个服务(在这里一个方法代表一个服务功能),我们需要具体的实现类来实现真正的服务。

2.实现类是UCServiceImpl.java

public class UCServiceImpl implements UcService {
private static Logger pointrecordlog = Logger.getLogger( "pointrecordlog" );
private static Logger logger = Logger.getLogger (UCServiceImpl. class );
private UcFacade ucFacade ;
public void setUcFacade(UcFacade ucFacade) {
this . ucFacade = ucFacade;
} public UserInfo getUserInfobyName(String userName) {
UserInfo user = null ;
try {
user = ucFacade .getUserInfoDetail(userName);
logger .debug( "get userinfo success by username:" + userName);
} catch (Throwable t) {
logger .error( "get userinfo fail by username:" + userName, t);
}
return user;
} public int recordLog(String username, String point, String operate, String desc) {
int result = 0;
try {
pointrecordlog .info(username + " - " + point + " - " + operate + " - " + desc);
} catch (Throwable t) {
result = -1;
logger .error(t);
}
return result;
}
}

说明:ucFacade是通过spring注入的一个数据查询类,因为它与http invoker没有直接关系,所以不进行介绍。

3.公开服务UcService.java

  WEB-INF/application-context.xml:将接口声明为HTTP invoker服务

< bean id = "httpService" class = "org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter" >
< property name = "service" >
< ref bean = "ucService" />
</ property > < property name = "serviceInterface" value = "com.netqin.baike.service.UcService" >
</ property >
</ bean > < bean id = "ucService" class = "com.netqin.baike.service.impl.UCServiceImpl" />

说明:HttpInvokerServiceExporter实际上是一个spring mvc控制器,它处理客户端的请求并调用服务实现。

WEB-INF/service-servlet.xml:HttpInvokerServiceExporter实际上是一个spring mvc控制器,所以需要为其提供spring URL 处理器,这里我们使用SimpleUrlHandlerMapping

< bean class = "org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" >
< property name = "mappings" >
< props >
< prop key = "/httpService" > httpService </ prop >
</ props >
</ property >
</ bean >

WEB-INF/web.xml:配置spring监听及DispatcherServlet

< context-param >
< param-name > contextConfigLocation </ param-name >
< param-value >
/WEB-INF/application-context.xml
</ param-value >
</ context-param > < listener >
< listener-class >
org.springframework.web.context.ContextLoaderListener
</ listener-class >
</ listener > < servlet >
< servlet-name > service</ servlet-name >
< servlet-class >
org.springframework.web.servlet.DispatcherServlet
</ servlet-class >
< load-on-startup > 1 </ load-on-startup >
</ servlet > < servlet-mapping >
< servlet-name > service </ servlet-name >
< url-pattern > /service/* </ url-pattern >
</ servlet-mapping >

说明:不了解为什么这么配置的可以去看看spring mvc方面的资料。

好了,经过以上配置,一个基于spring HTTP invoker的远程服务就完成了,服务的地址为:

http://${serviceName}:${port}/${contextPath}/service/httpService

客户端

1. 创建服务接口及网络间传输的DTO类

  为了方便,可以将服务器端创建好的的UcService.java和UserInfo.java拷贝到客户端,或打个jar包放到lib下。

2.  配置访问服务

  WEB-INF/application-context.xml:如果项目中已经存在spring配置文件,则不需要创建该文件,需要配置HTTP invoker的代理

< bean id = "httpService" class = "org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean" >
< property name = "serviceUrl" >
< value > http://${serviceName}:${port}/${contextPath}/service/httpService
</ value >
</ property > < property name = "serviceInterface"
value = "com.netqin.baike.service.UcService" >
</ property >
</ bean >

说明:客户端使用HttpInvokerProxyFactoryBean代理客户端向服务器端发送请求,请求接口为UcService的服务

注意:需要修改serviceUrl为实际的服务器地址

WEB-INF/web.xml:配置spring监听

如果项目没有spring环境,则需要在web.xml中加入对spring的支持

< context-param >
< param-name > contextConfigLocation </ param-name >
< param-value >
/WEB-INF/application-context.xml
</ param-value >
</ context-param > < listener >
< listener-class >
org.springframework.web.context.ContextLoaderListener
</ listener-class >
</ listener >

3.       访问服务方法

  读取spring上下文,以远程调用getUserInfobyName方法为例

  在jsp,servlet,action等等文件中

UcService service = (UcService) WebApplicationContextUtils.getRequiredWebApplicationContext(
request.getSession().getServletContext()).getBean("httpService" ); UserInfo user = service .getUserInfobyName( "hanqunfeng" );

如果不想配置spring运行环境,可以使用如下方式:

ApplicationContext applicationContext = new FileSystemXmlApplicationContext( "classpath:application-context.xml" );

service = (UcService) applicationContext.getBean( "httpService" );

依赖注入,远程调用recordLog方法为例

在WEB-INF/application-context.xml中加入如下配置:

< bean id = "abc" class = "com.netqin.test.abc" >
< property name = "service" >
< ref bean = "httpService" />
</ property >
</ bean >

为com.netqin.test.abc中加入对service的set方法:

private UcService service ;

public void setService(UcService service){
this . service = service;
} public String recordUserLog(String username,String point,String operate,String desc){
String result = service .recordLog(username, point, operate, desc);
return result;
}

关于服务器端配置的补充说明:

有一个误区:有些关于springMVC的书 上说,如果没有明确声明一个处理适配器,默认会使用org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,这个适配器 专门负责处理所有实现了

org.springframework.web.servlet.mvc.Controller接口的处理器,我就是受其影响,认为org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter实现的是org.springframework.web.HttpRequestHandler接口,所以按理说应该使用的处理适配器是org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,但实际上并不会出现异 常。

其实,原因是因为spring默认会使用四个处理适配器(参看DispatcherServlet.properties,spring2.5,spring2.0只默认三个,2.5增加注解方式):

org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,/ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,/ org.springframework.web.servlet.mvc.throwaway.ThrowawayControllerHandlerAdapter,/ org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

关于DispatcherServlet.properties的详细信息可以参看:

http://blog.csdn.net/hanqunfeng/archive/2010/01/08/5161319.aspx

但是,如果明确声明了其它的处理适配器,比如org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter, 等等,则默认规则则会覆盖,需要明确声明org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter这个处理适配器,否则系 统会抛异常:

javax.servlet.ServletException: No adapter for handler  [org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter@179bd14]: Does your handler implement a supported interface like Controller?

所以,建议在使用spring invoker时,最好明确声明org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter这个处理适配器。

原文链接:http://hanqunfeng.iteye.com/blog/868210

Spring HTTP invoker简介的更多相关文章

  1. Spring Http Invoker使用简介

    一.Spring HTTP Invoker简介 Spring HTTP invoker 是 spring 框架中的一个远程调用模型,执行基于 HTTP 的远程调用(意味着可以通过防火墙),并使用 ja ...

  2. Spring Web Flow 简介

    Spring Web Flow 简介 博客分类: 转载 SSH 最近在TSS上看到了一片介绍Spring Web Flow的文章,顺便就翻译了下来,SWF的正式版估计要到6月份才能看到了,目前的例子都 ...

  3. 服务调用方案(Spring Http Invoker) - 我们到底能走多远系列(40)

    我们到底能走多远系列(40) 扯淡:  判断是否加可以效力于这家公司,一个很好的判断是,接触下这公司工作几年的员工,了解下生活工作状态,这就是你几年后的状态,如果满意就可以考虑加入了. 主题: 场景: ...

  4. Spring中AOP简介与切面编程的使用

    Spring中AOP简介与使用 什么是AOP? Aspect Oriented Programming(AOP),多译作 "面向切面编程",也就是说,对一段程序,从侧面插入,进行操 ...

  5. Unit03: Spring Web MVC简介 、 基于XML配置的MVC应用 、 基于注解配置的MVC应用

    Unit03: Spring Web MVC简介 . 基于XML配置的MVC应用 . 基于注解配置的MVC应用 springmvc (1)springmvc是什么? 是一个mvc框架,用来简化基于mv ...

  6. spring 拦截器简介

    spring 拦截器简介 常见应用场景 1.日志记录:记录请求信息的日志,以便进行信息监控.信息统计.计算PV(Page View)等.2.权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直 ...

  7. Spring Boot 之Spring data JPA简介

    文章目录 添加依赖 添加entity bean 创建 Dao Spring Data Configuration 测试 Spring Boot 之Spring data JPA简介 JPA的全称是Ja ...

  8. Spring HTTP invoker 入门

    一.简介 Spring开发团队意识到RMI服务和基于HTTP的服务(如,Hessian)之间的空白.一方面,RMI使用JAVA标准的对象序列化机制,很难穿透防火墙.另一方面,Hessian/Burla ...

  9. Spring MVC+FreeMarker简介

    最近做项目,刚接触到SpringMVC与FreeMarker框架,就简单介绍一下自己的理解,不正确的地方请大家指教!! 1.Spring MVC工作原理: 用户发送请求--->前端服务器去找相对 ...

随机推荐

  1. vector容器、

    一.  vector  向量容器1. 创建   vector  对象(1)不指定容器大小vector<int> V;(2)指定容器大小vector<int> V(10);(3) ...

  2. 2018-2-25-git-rebase-合并多个提交

    title author date CreateTime categories git rebase 合并多个提交 lindexi 2018-02-25 11:41:26 +0800 2018-2-1 ...

  3. Redux 认识之后进阶

    两个东西 action  状态 路由 以及嵌套路由 完整结构   进阶+源代码 源代码在我的 gitHub  存储库里面  https://github.com/Haisenan/Redux2.0

  4. 2019-1-29-WPF-设置输入只能英文

    title author date CreateTime categories WPF 设置输入只能英文 lindexi 2019-1-29 15:8:4 +0800 2018-2-13 17:23: ...

  5. 喵喵电影git操作

    1.git remote 2.git remote add origin '项目地址'   (origin为远程仓库名字) 3.git remote 4.git push origin master ...

  6. thinter图形开发界面

    tkinter编程步骤 导入Tkinter 创建控件 import thinter 创建主窗口 #win = tkinter.Tk() 设置标题 win.title("xiaoxin&quo ...

  7. 【23.91%】【hdu 4694】Important Sisters("支NMLGB配树"后记)(支配树代码详解)

    Time Limit: 7000/7000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Total Submission( ...

  8. javascript拷贝

    function copy(obj){ //浅拷贝 var result = {}; for(var attr in obj){ result[attr] = obj[attr]; } return ...

  9. 最全最详细的PHP面试题(带有答案)

    这篇文章介绍的内容是关于最全最详细的PHP面试题(带有答案),有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 相关推荐: 分享一波腾讯PHP面试题 2019年PHP最新面试题(含答案) ...

  10. 原生JS数组方法实现(一)————push()、unshift()、pop()和shift()

    push 向数组末尾添加一个或多个元素,并返回数组新的长度 ```javascript function push(){ for(let i=0;i<arguments.length;i++){ ...