Spring的远程服务

  由于项目的关系,接触到spring的远程服务调用,我主要复杂服务端的业务逻辑开发,而且先前的架子已经搭好了,所以先前并未感觉到发布服务的存在,等到想仔细看看远程服务是怎么配置的时候才发现没有看懂,没办法只有看看《Spring in Action》,总算略知一二了。相比起Spring的标准配置而言,项目的配置反而更复杂点,复杂在于那些个有关远程服务的spring bean的配置都是个性化以后的,参数的设置都和标准不同,难怪我看不懂了,不过你如果熟悉原理以后就会发现万变不离其中。 

    为了方便日后复习或者文档的完善的目的,还是现学现卖,看看spring中如何借助自己的组件发布我们的远程服务。

  在Spring中提供了四种类型的远程服务:RMI(老东西),Hessian或BurLap,HTTP invoker,SOAP。如果我们去使用其中的任何一种去发布和调用远程服务,其过程也大致相同。一个一个来吧。以下内容来自对《Spring in Action》的理解。或者可以参考spring 2.0 reference中

写道

http://www.redsaga.com/spring_ref/2.0/html/remoting.html

 

  •    RMI。没有Spring,这个老家伙要用起来还真是麻烦,还要注册,编译什么的。最好的无侵入的框架就是让使用者基本感受不到组件的存在。在服务端,我们就像开发本地的服务一样开发,至于远程的客户端怎么调用我这个服务那就交给Spring做吧,就像一个代理一样。现实中的中介就是这么个作用,在spring中叫做代理。
  • Hessian或Burlap,这两个东东本质上是一样的,只不过前者是二进制流的方式传输,后者是xml消息的方式传输。另外一点就是他们都是基于http的,所以在服务器端就多了一步要配置相关的servelet,dispatcher,controller。
  • Http invoker当然是基于http 的了,所以大致上的配置和Hessian(或Burlap)相同。不同的是是这个是Spring小组自己开发的一直远程服务模型。Spring HTTP调用器使用标准Java序列化机制来通过HTTP暴露业务。如果你的参数或返回值是复杂类型,并且不能通过Hessian和Burlap的序列化机制进行序列化,HTTP调用器就很有优势。
  • soap 暂时不说。如果是客户端调用soap,用spring配置客户端即可,客户端才不去管服务器端是不是用java写的程序。这点与上述三种不一样。  

如果你曾经使用过HTTP invoker来发布过你的服务的话,那么以下的几个类你应该很熟悉了,HttpInvokerProxyFactoryBean,HttpInvokerServiceExporter,DispatcherServlet,BeanNameUrlHandleMapping.

尤其是后面两个。以下是我的对一个远程服务请求过来的在代码层次spring都在干些什么。

场景如下:

   客户端的配置如下:

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="accountService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean"> <property name="serviceUrl"> <value> http://127.0.0.1:8080/TestService-server/remoting.service</value> </property> <property name="serviceInterface"> <value>test.AccountService </value> </property> </bean> </beans>
 

 

  服务器端:

  web.xml部分内容

 

<servlet> <servlet-name>remoting</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>remoting</servlet-name> <url-pattern>*.service</url-pattern> </servlet-mapping>
 

 

  remoting-servelet.xml

 

<beans> <bean id="accountService" class="test.AccountServiceImpl"> <!-- any additional properties, maybe a DAO? --> </bean> <bean name="/remoting.service" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter"> <property name="service" ref="accountService" /> <property name="serviceInterface" value="test.AccountService" /> </bean> </beans>
 

 

好了:现在服务器开始启动了。我们只关心我们感兴趣的地方,先睹为快吧,看看那只tomcat的log

2008-11-21 17:23:57,906 DEBUG [org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping] - Looking for URL mappings in application context: org.springframework.web.context.support.XmlWebApplicationContext: display name [WebApplicationContext for namespace 'remoting-servlet']; startup date [Fri Nov 21 17:23:57 CST 2008]; root of context hierarchy; config locations [/WEB-INF/remoting-servlet.xml]
2008-11-21 17:23:57,906 DEBUG [org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping] - Rejected bean name 'accountService'
2008-11-21 17:23:57,906 DEBUG [org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping] - Found URL mapping [/remoting.service]
2008-11-21 17:23:57,906 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean '/remoting.service'
2008-11-21 17:23:57,906 DEBUG [org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping] - Mapped URL path [/remoting.service] onto handler [org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter@11f139b]
2008-11-21 17:23:57,906 INFO [org.springframework.web.servlet.DispatcherServlet] - No HandlerMappings found in servlet 'remoting': using default
2008-11-21 17:23:57,906 DEBUG [org.springframework.core.CollectionFactory] - Creating [java.util.LinkedHashMap]
2008-11-21 17:23:57,921 INFO [org.springframework.web.servlet.DispatcherServlet] - No HandlerAdapters found in servlet 'remoting': using default
2008-11-21 17:23:57,921 DEBUG [org.springframework.core.CollectionFactory] - Creating [java.util.LinkedHashMap]
2008-11-21 17:23:57,921 DEBUG [org.springframework.core.CollectionFactory] - Creating [java.util.LinkedHashMap]
2008-11-21 17:23:57,937 INFO [org.springframework.web.servlet.DispatcherServlet] - No ViewResolvers found in servlet 'remoting': using default
2008-11-21 17:23:57,937 INFO [org.springframework.web.servlet.DispatcherServlet] - FrameworkServlet 'remoting': initialization completed in 484 ms
2008-11-21 17:23:57,937 INFO [org.springframework.web.servlet.DispatcherServlet] - Servlet 'remoting' configured successfully

大部分是关于 DispatcherServlet的log。下面看看服务端的两个比较重要的类:

 

 httpInvokeServiceExporter和SimpleUrlHandleMaping,有的时候可以只用前者就可以,这个时候默认使用

BeanNameUrlHandleMapping。后者负责请求url和bean的映射,前者复杂将指定的bean导出成http invoke service。
原文如下:Web controller that exports the specified service bean as HTTP invoker service endpoint,

accessible via an HTTP invoker proxy.
实现SimpleUrlHandleMaping的实例在初始化的时候会调用initApplicationContext()方法,这个方法是其父类

ApplicationObjectSupport的方法,通过重写initApplicationContext()
我们可以实现自己的url Mapping逻辑,事实上继承自AbstractUrlHandlerMapping的两个子类SimpleUrlHandleMaping,

BeanNameUrlHandleMapping也是这么干的。

在自定义的initApplicationContext()方法中一般会实现自定义的解析url的逻辑,然后根据url和handle的关系作为键值

对保存在AbstractUrlHandlerMapping.handlerMap
中去,这样每当以后有远程service请求过来的时候我们就调用getHandlerInternal(HttpServletRequest request)去到

handleMap中去找对应的handle。
那handle是个什么东东呢,handle一般是实现httpInvokeServiceExporter的一个实例,而且设置了service,

serviceInterface等属性,可以通过httpInvokerProxy访问。。

好,到这里一些大概可以想像的东西可以想到了,客户端提交了一个请求比如:http://127.0.0.1:8080/TestService-

server/remoting.service,当这个请求
到达服务器端的时候,负责处理这些个url的servelet正等着呢,很容易理解这个请求被抛给了remoting这个

DispatcherServelet。
<servlet>
 <servlet-name>remoting</servlet-name>
 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
 <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
 <servlet-name>remoting</servlet-name>
 <url-pattern>*.service</url-pattern>
</servlet-mapping>
在没有弄清楚具体的实现逻辑之前,我们仍然可以想象一下大致的过程。DispatcherServelet会找到对应的控制器也就是

BeanNameUrlHandleMapping,然后调用
getHandlerInternal(HttpServletRequest request)方法得到一个handle。

DispatcherServelet本身也是一个HttpServlet在初始化的时候会调用inti,在初始化的过程中会调用

initHandlerMappings(),这个方法
将实现HandlerMapping接口的全部保存在handlerMappings中,比如BeanNameUrlHandleMapping
。等到DispatcherServelet需要处理processRequest时,dispatcher会调用getHandler去调用BeanNameUrlHandleMapping

的getHandle
返回包装过Handle的HandlerExecutionChain,如return new HandlerExecutionChain(handler,

this.adaptedInterceptors);
随后dispatcher会在doDispatch()中做处理,代码如下:
// Actually invoke the handler.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

其实到这里服务端的工作差不多了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值