我已经按照弹簧远程处理的教程,特别是HttpInvokerServiceExporter
,并且在设置客户端和服务器(factorybean)时都没有问题。
问题是,我注意到使用Spring MVC,每个接口都映射到一个特定的URL
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="hello.htm">test_service</prop>
</props>
</property>
</bean>
<!-- *********************exposed web services*************************-->
<bean name="test_service" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="serviceInterface" value="foo.webservices.HelloServiceInterface" />
<property name="service">
<ref bean="helloService"></ref>
</property>
问题是,如果我的服务接口中有多个方法,是否可以将这些接口方法中的每一个映射到URL本身?
答案 0 :(得分:4)
HTTPInvokerServiceExporter
背后的想法是提供一个端点来接收删除方法调用。
在服务器方面,配置一个RemoteExporter
会很容易,声明要公开的接口并将其与将处理调用的真实bean相关联。
在客户端上,有必要配置基本上需要在服务器端访问的接口的RemoteAcessor
。
可以使用服务器端的HttpInvokerServiceExporter完成HTTP上的实现,如下例所示:
服务接口:
package foo.bar.services;
public interface MyService {
public int sum(int num1, int num2);
}
对于这项服务,您将有一个实现(假设为foo.bar.services.DefaultMyService
)。
春季背景的展示和配置如下:
<bean name="myService" class="foo.bar.DefaultMyService" />
<bean name="/myService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="service" ref="myService"/>
<property name="serviceInterface" value="foo.bar.MyService"/>
</bean>
使用这种配置,我只是打算在最简单的情况下使用MyService
(bean名称)映射的URL在foo.bar.MyService
接口下公开我的/myService
实现的实例BeanNameUrlHandlerMapping
除了使用URL值(这种情况/myService
)将URL映射到bean之外别无其他。
在客户端(使用者),您将配置一个bean,只是声明您希望远程端暴露的接口。对于我们的服务将是这样的:
<bean id="httpInvokerProxy" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl" value="http://foo.bar.org/springSample/myService"/>
<property name="serviceInterface" value="foo.bar.MyService"/>
</bean>
当spring在客户端实例化bean时,会实例化一个代理,然后每个方法调用都会被序列化并通过HTTP发送到端点(在本例中为http://foo.bar.org/springSample/myService
。在服务器端,此请求是反序列化和解释,即调用暴露的实际服务上的方法(在我们的案例中为DefaultMyService)。服务将返回一些将被序列化的内容,作为客户端执行的HTTP请求的结果。客户端将接收它并反序列化它并将其返回给原始方法调用器。
正如您所看到的(并从Spring文档中获得):
服务器端将
反序列化远程调用对象并序列化远程 调用结果对象。像RMI一样使用Java序列化,但是 提供与Caucho的基于HTTP的Hessian和 粗麻布协议。
客户端将
序列化远程调用对象并反序列化远程 调用结果对象。像RMI一样使用Java序列化,但是 提供与Caucho的基于HTTP的Hessian和 粗麻布协议。
在这种情况下与Spring Remoting一起使用的序列化是Java序列化,这意味着HTTP请求包含一个包含序列化对象的实体主体(请记住,在这种情况下,JVM版本和类版本需要兼容)。
博览会作为一个整体完成,你不能将它与该界面的每个方法分开一个URL
。因此,更容易使用Spring MVC并创建一个控制器(@Controller
)为您的接口上的每个方法实现一个方法,将其注释为@RequestMapping
(使用所需的URL)并调用方法服务如下:
控制器示例
package foo.bar;
import foo.bar.service.MyService;
@Controller
public class MyService {
@Autowired
private MyService myService;
@RequestMapping("/sum/{num1}/{num2}")
public int sum(@PathVariable("num1") int num1, @PathVariable("num2") int num2) {
return myService.sum(num1, num2);
}
}
使用上下文配置
<context:component-scan base-package="foo.bar"/>
它会自动映射foo.bar和包下的类,这意味着Service
实现(DefaultMyService
)可以与@Service
和@Autowired
映射到控制器在示例中完成,在上下文xml上没有任何bean配置。
但这将通过REST接口公开您的服务,这意味着它将处理可由其他消费者(如PHP使用者)完成的HTTP普通请求(这不能通过Spring Remoting完成,因为它使用纯Java序列化)。 / p>
如果您的客户端是Java,您可以明确地使用远程处理并将您的服务作为一个整体公开,如果不是,使用Spring MVC的REST实现是一个很好的解决方案。
可以找到Spring文档here
答案 1 :(得分:1)
我真的建议使用@Controller注释定义控制器。从Spring documentation开始,将组件扫描添加到Spring配置中。
<context:component-scan base-package="your.package.path"/>
然后,在类中,例如your.package.path.WhateverController,注释该类:
@Controller
WhateverController
使用@RequestMapping注释你的方法:
@RequestMapping(value = "/helloWorld")
public ModelAndView helloWorld() {
...
}
@RequestMapping(value = "/project/{projectId}")
public ModelAndView helloWorld(@PathVariable String projectId) {
...
}
就是这样,每个控制器有多个映射。
答案 2 :(得分:1)
我想你需要先告诉我们你要做什么。如果您将服务公开给通用Web客户端,REST或SOAP将是更好的选择;如果您将服务暴露给另一个应用程序中的另一个Spring bean,那么Spring Remoting就足够了。
您的弹簧配置文件中的“公开的Web服务”注释似乎不清楚您的目的。
当您向远程客户端公开服务时,您始终需要提供合同以让远程客户端知道可能的内容。 REST使用URL公开该合同; SOAP使用WSDL公开该合同;而Spring Remoting只是直接给客户端在java接口中签约,因此客户端可以将该接口注入到自己的bean中,并像本地定义的bean一样使用它。
在您的问题中,您提到将方法映射到URL,Spring Remoting不能这样做,因为它暴露了接口;你想做什么听起来很震撼我。我同意@stevebrown,使用映射控制器公开您的服务是一种很好的方法。