一、远程调用概述

  1.远程调用的定义

    在一个程序中就像调用本地中的方法一样调用另外一个远程程序中的方法,但是整个过程对本地完全透明,这就是远程调用。spring已经能够非常成熟的完成该项功能了。

  2.spring远程调用的原理

    客户端调用本地接口中的一个方法调用的时候将会被客户端代理拦截,并向远程服务器发起一个servlet请求(服务器中的web.xml文件中专门配置了该Servlet),服务器接受请求,并根据spring配置文件和请求的url找到对应的“导出器”,导出器将pojo转换成控制器controller,并最终完成请求的任务,并将结果以流的形式返回到客户端,客户端由此拿到额执行结果的数据。

    服务端和客户端之间通信使用的是序列化对象类型,之后会说明该问题。

  3.使用远程调用的好处是什么

    实现了远程调用的程序能够对外提供一种“服务”,其它程序能够不必重写它的功能模块就能够实现某个功能,其它程序所需要做的仅仅只是一句调用的代码而已。这样做能够极大的提高开发效率。

    以当前的数据采集系统为例,已经实现了对数据的统计功能,但是其它网站想要重用你的代码就很困难了,比如其它网站在我们的数据采集系统中新建了调查,调查完毕之后其它网站想要获取统计结果数据并在自己的应用程序中进行统计,这时候获取统计数据就是比较重要的事情了

  4.获取统计结果的方法

  (1).在数据采集系统中使用“导出到XML”文件或者“导出到Excel文件”的功能将数据导出到文件中,然后在自己的应用程序中对这些数据进行分析。使用这种方式不仅需要分析数据,还要自己进行统计代码的书写,是一种非常笨的方法。

  (2).使用数据采集系统提供的公共接口,直接远程调用对应接口中的方法,实现过程对本地透明。获取的数据是已经完全封装好的数据,直接使用即可。但是使用这种方式需要两个程序都使用spring环境(java环境),而且客户端需要拥有接口和相关bean的class文件。

  5.总结。

    综合以上两方面使用第二种方式是更为理想的方式,但是缺点也是很明显的,那就是强制两端都使用spring环境。能够有折中方案呢?即能够有类似于远程调用的功能,但是不用强制限制客户端使用spring或者java环境,解决方案就是使用WebService,使用WebService虽然解决了以上的矛盾问题,但是它本身也有缺点,那就是效率比较低。从中可以看出使用远程调用和使用WebService各有优劣之处,应当根据不同的环境使用不同的方法。

    当两端程序都是用Spring环境的情况下,使用远程调用提供外部服务;当其中有一端不使用Spring的时候,使用WebService

二、Spring实现远程调用Demo案例

    源代码地址:https://github.com/kdyzm/day78_spring_rpc_demo/blob/master/readme.md

  1.在Eclipse下创建一个Web项目,RPC_Server和一个普通java项目:RPC_Client

  2.在RPC_Server上配置远程调用服务

    首先将Spring的相关jar包加上:特别是下面强调部分的jar包,是远程实现远程调用的核心jar包。

    com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
    com.springsource.net.sf.cglib-2.2.0.jar
    com.springsource.org.aopalliance-1.0.0.jar
    com.springsource.org.apache.commons.codec-1.3.0.jar
    com.springsource.org.apache.commons.logging-1.1.1.jar
    com.springsource.org.aspectj.tools-1.6.6.RELEASE.jar
    com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
    com.springsource.org.quartz-1.6.2.jar
    commons-lang-2.5.jar
    log4j.jar
    org.springframework.aop-3.1.0.RELEASE.jar
    org.springframework.asm-3.1.0.RELEASE.jar
    org.springframework.aspects-3.1.0.RELEASE.jar
    org.springframework.beans-3.1.0.RELEASE.jar
    org.springframework.context-3.1.0.RELEASE.jar
    org.springframework.context.support-3.1.0.RELEASE.jar
    org.springframework.core-3.1.0.RELEASE.jar
    org.springframework.expression-3.1.0.RELEASE.jar
    org.springframework.jdbc-3.1.0.RELEASE.jar
    org.springframework.orm-3.1.0.RELEASE.jar
    org.springframework.transaction-3.1.0.RELEASE.jar
    org.springframework.web-3.1.0.RELEASE.jar
    org.springframework.web.servlet-3.1.0.RELEASE.jar
    slf4j-api-1.5.8.jar
    slf4j-log4j12.jar

  3.配置web.xml文件(分发器配置),加入一个Servlet的配置

 <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>RPC_Server</display-name>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>*.service</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>

  4.创建WelcomeService接口和WelcomeServiceImpl实现类

 package com.kdyzm.rpc.server;

 public interface WelcomeService {
public String say(String name);
}
 package com.kdyzm.rpc.server;

 public class WelcomServiceImpl implements WelcomeService{

     @Override
public String say(String name) {
System.out.println("你好,"+name);
return name;
}
}

  5.将Service注入spring容器,最重要的还要配置好导出器

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/tx/spring-tx-2.5.xsd">
<bean id="welcomeService" class="com.kdyzm.rpc.server.WelcomServiceImpl"></bean>
<bean class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter" name="/ws.service">
<property name="serviceInterface">
<value>com.kdyzm.rpc.server.WelcomeService</value>
</property>
<property name="service" ref="welcomeService"></property>
</bean>
</beans>

  6.浏览器测试

    (1)结果显示

    将服务端的程序发布到tomcat,在浏览器上访问http://localhost:8080/RPC_Server/ws.service,观察浏览器显示结果。

  

    如果显示这样的信息表示服务端已经配置成功了。为什么会是这样呢?因为服务端提供的不是http服务,而是应用程序的服务,必须使用正确的客户端才能正确的访问。

    (2)原因分析

      先做好7.中的客户端程序,然后进行下面的流程。

      之所以会出现这种现象,是因为远程调用的时候客户端和服务端之间的数据传递使用的是序列化对象的形式,可以使用eclipse自带的TCP/IP监视器查看,关于它的用法就是将客户端的请求端口改成监视端口,该监视器会将从指定监听端口上监听到的流量转发到实际请求的端口号,服务器响应的时候则反过来。

      

    最终捕获到到的请求和相应信息:

  7.RPC_Client配置

    (1)添加类库

      将RPC_Server中的依赖类库完完整整的拷贝到RPC_Client中。然后将接口WelcomeService也拷贝到该项目中,但是实现类WelcomeServiceImpl就不要拷贝到项目中了。

    (2)配置Spring的配置文件

      实际上客户端的配置文件只需要配置一处地方就可以了,配置的是客户端代理。

 <bean id="wsClient" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceInterface">
<value>com.kdyzm.rpc.client.WelcomeService</value>
</property>
<property name="serviceUrl">
<value>http://localhost:8080/RPC_Server/ws.service</value>
</property>
</bean>

    该配置实际上建立了本地接口和远程Servlet之间的一个映射关系,当在本地访问配置的Service接口的时候,代理会向远程服务器发起远程访问,访问的正是之前在服务器中配置的servlet访问地址。

  完整的配置为:

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/tx/spring-tx-2.5.xsd">
<!-- 配置客户端代理 -->
<bean id="wsClient" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceInterface">
<value>com.kdyzm.rpc.client.WelcomeService</value>
</property>
<property name="serviceUrl">
<value>http://localhost:8080/RPC_Server/ws.service</value>
</property>
</bean>
</beans>

    (3)接下来书写测试类,测试类非常简单,只需要拿到注入的Service对象,然后调用接口中的方法即可。

 public class Main{
public static void main(String args[]){
3  ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
4  WelcomeService service=(WelcomeService) context.getBean("wsClient");
5  service.say("狗蛋");
6  }
}

    (4)运行测试程序,查看客户端和服务端控制台的打印结果

      这里是显示的是tomcat打印的结果,也就是说客户端已经正确访问了服务端的程序。调用了服务端的方法。

      到这里spring远程调用的实现已经完成了。

三、将数据采集系统中的SurveyService接口配置为公共的服务接口。

  已经有了之前的例子,将当前的数据采集系统中的SurveyService配置成为接口,实现spring的远程调用也就非常简单了。

  1.首先还是在web.xml配置文件中配置分发器

 <!-- 配置spring远程调用使用的分发器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>*.service</url-pattern>
</servlet-mapping>

  2.将服务类纳入Spring容器管理。

    服务接口是SurveyService,实现类是SurveyServiceImpl,在项目中之前都已经写好了,而且不需要使用XML的形式纳入Spring容器管理,它们都是用注解的形式纳入了Spring容器中并进行了配置。

  3.配置spring配置文件,这里只需要进行一个导出器的配置即可。

 <!-- 配置Spring远程调用服务端 -->
<bean name="/surveyService.service" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="serviceInterface" value="com.kdyzm.service.SurveyService"></property>
<property name="service" ref="surveyService"></property>
</bean>

  4.浏览器测试,显示500错误,表示配置spring的远程调用没有问题。

  

  到此为止,服务端已经配置完成。

  5.客户端的配置

    (1)为了简化处理,将相关类能够直接使用,直接将服务端加入到客户端的classpath,这样就能够直接使用服务端自定义的类了。

    方法:项目右键->build path->config build path->projects,选择LSN_surveypark项目,这样LSN_surveypark项目就变成了RPC_Client的依赖项目了。

    (2)配置spring配置文件。

 <bean id="surveyClient" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceInterface">
<value>com.kdyzm.service.SurveyService</value>
</property>
<property name="serviceUrl">
<value>http://localhost:8080/LSN_ServyPark/surveyService.service</value>
</property>
</bean>

    (3)这样客户端就配置完成了。

  6.直接在客户端进行测试即可。

  这里以获取所有可用的调查为例进行测试,注意各个Bean对象最好都是先实现Serialize接口,这样才能进行网络传输。否则的话服务端首先会报错,因为无法序列化。

  测试代码:

 package com.kdyzm.rpc.client;

 import java.util.Collection;

 import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import com.kdyzm.domain.Page;
import com.kdyzm.domain.Question;
import com.kdyzm.domain.Survey;
import com.kdyzm.service.SurveyService; public class Main {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
/*WelcomeService service=(WelcomeService) context.getBean("wsClient");
service.say("狗蛋");*/
SurveyService surveyService=(SurveyService) context.getBean("surveyClient");
Collection<Survey>surveys=surveyService.getAllAvailableSurveys();
for(Survey survey:surveys){
System.out.println(survey.getSurveyId()+"_"+survey.getTitle());
//使用transient关键字实现对字段的屏蔽(不序列化)
if(survey.getPages()!=null)
for(Page page:survey.getPages()){
System.out.println("\t"+page.getPageId()+"_"+page.getOrderNo());
for(Question question:page.getQuestions()){
System.out.println("\t\t"+question.getQuestionId()+"_"+question.getTitle());
}
}
}
}
}

    运行程序,显示查看控制台显示的结果信息。

  

    显示的结果是一共有8个可用的调查,这些打印结果都是封装到对象之后传输过来的。之前的错误信息提示就忽略即可,是jar包冲突导致的问题,不影响测试结果。

四、spring远程调用功能完成。

      

【Java EE 学习 78 中】【数据采集系统第十天】【Spring远程调用】的更多相关文章

  1. 【Java EE 学习 69 中】【数据采集系统第一天】【SSH框架搭建】

    经过23天的艰苦斗争,终于搞定了数据采集系统~徐培成老师很厉害啊,明明只是用了10天就搞定的项目我却做了23天,还是模仿的...呵呵,算了,总之最后总算是完成了,现在该好好整理该项目了. 第一天的内容 ...

  2. 【Java EE 学习 78 上】【数据采集系统第十天】【Service使用Spring缓存模块】

    一.需求分析 调查问卷中或许每一个单击动作都会引发大量的数据库访问,特别是在参与调查的过程中,只是单击“上一页”或者“下一页”的按钮就会引发大量的查询,必须对这种问题进行优化才行.使用缓存策略进行查询 ...

  3. 【Java EE 学习 78 下】【数据采集系统第十天】【数据采集系统完成】

    一.项目源代码地址 二.项目演示

  4. 【Java EE 学习 80 上】【WebService】

    一.WebService概述 什么是WebService,顾名思义,就是基于Web的服务,它使用Http方式接收和响应外部系统的某种请求,从而实现远程调用.WebService实际上就是依据某些标准, ...

  5. Java EE学习——Quartz的Cron表达式

    经历过低谷后,还是要好好学习,越失落会越来越落后. 今天写一下Cron表达式的用法,虽然是之前自己写的,也过了挺长一段时间,这次就拿出来作为回顾吧. Cron表达式是Quartz的精髓(个人觉得),比 ...

  6. Java EE 学习(9):IDEA + maven + spring 搭建 web(5)- 博客文章管理

    转载:Gaussic(一个致力于AI研究却不得不兼顾项目的研究生) . 注:在阅读本文前,请先阅读: Java EE 学习(5):IDEA + maven + spring 搭建 web(1) Jav ...

  7. Java EE 学习(8):IDEA + maven + spring 搭建 web(4)- 用户管理

    转载:Gaussic(一个致力于AI研究却不得不兼顾项目的研究生) 注:在阅读本文前,请先阅读: Java EE 学习(5):IDEA + maven + spring 搭建 web(1) ava E ...

  8. Java EE 学习(7):IDEA + maven + spring 搭建 web(3)- 配置数据库

    参考: https://my.oschina.net/gaussik/blog/513444 注:在阅读本文前,请先阅读: Java EE 学习(5):IDEA + maven + spring 搭建 ...

  9. Java EE 学习(6):IDEA + maven + spring 搭建 web(2)- 配置 Spring

    参考:https://my.oschina.net/gaussik/blog/513353 注:此文承接上一文:Java EE 学习(5):IDEA + maven + spring 搭建 web(1 ...

随机推荐

  1. Premiere使用整理

    整理部分自己在使用Premiere CC中遇到的问题和注意点. 1. 新建序列 若是录屏文件,可选择已加入到项目中的视频文件,点击 文件-新建-来自剪辑的序列. 2. 新建字幕 用于在视频中添加文字. ...

  2. iBatis.net 循环iterate,没有foreach

    3.9.4. Iterate Element This tag will iterate over a collection and repeat the body content for each ...

  3. centos 7.0 编译安装php 7.0.3

    php下载页面 http://cn2.php.net/downloads.php 7.0.3多地区下载页面 http://cn2.php.net/get/php-7.0.3.tar.gz/from/a ...

  4. 抓取百万知乎用户信息之HttpHelper的迭代之路

    什么是Httphelper? httpelpers是一个封装好拿来获取网络上资源的工具类.因为是用http协议,故取名httphelper. httphelper出现的背景 使用WebClient可以 ...

  5. centos7 cannot find a valid baseurl for repo base (转载)

    centos7 cannot find a valid baseurl for repo base     今天在虚拟机下安装centosmini版本,安装后第一件事就是yum update 但是有错 ...

  6. 库AFNetworking的使用

    库AFNetworking的使用 1.GET请求(html,json,xml) #pragma mark -GET请求 -(void)testGetRequset{ NSString *urlStri ...

  7. HDOJ 4770 Lights Against Dudely

    状压+暴力搜索 Lights Against Dudely Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K ...

  8. hdu 4946 2014 Multi-University Training Contest 8

    Area of Mushroom Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) ...

  9. tfs连不上团队资源管理器问题

    这个问题主要原因是因电脑装了vs2008又装了vs2012,因为版本不一样,所以只需要将VersionControl.config这个文件删除掉就可以了.文件路径C:\Users\Administra ...

  10. HDU5934 强连通分量

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=5934 根据距离关系建边 对于强连通分量来说,只需引爆话费最小的炸弹即可引爆整个强连通分量 将所有的强连通分 ...