15.5.1 创建基于 Spring 的 JAX-WS 端点

在本章前面的内容中,我们使用 Spring 的服务导出器创建了远程服务。这些服务导出器很神奇地将 Spring 配置的 POJO 转换成了远程服务。我们看到了如何使用 RmiServiceExporter 创建 RMI 服务,如何使用 HessianServiceExporter 创建 Hessian 服务,如何使用 BurlapServiceExporter 创建 Burlap 服务,以及如何使用 HttpInvokerServiceExporter 创建 HTTP invoker 服务。现在你或许期望我在本节展示如何使用一个 JAX-WS 服务导出器创建 Web 服务。

Spring 的确提供了一个 JAX-WS 服务导出器,SimpleJaxWsServiceExporter,我们很快就可以看到。但在这之前,你必须知道它并不一定是所有场景下的最好选择。你是知道的,SimpleJaxWsServiceExporter 要求 JAX-WS 运行时支持将端点发布到指定地址上。Sun JDK 1.6 自带的 JAX-WS 可以符合要求,但是其他的 JAX-WS 实现,包括 JAX-WS 的参考实现,可能并不能满足此需求。

如果我们将要部署的 JAX-WS 运行时不支持将其发布到指定地址上,那我们就要以更为传统的方式来编写 JAX-WS 端点。这意味着端点的生命周期由 JAX-WS 运行时来进行管理,而不是 Spring。但是这并不 意味着它们不能装配 Spring 上下文中的 bean。

在 Spring 中自动装配 JAX-WS 端点

JAX-WS编程模型使用注解将类和类的方法声明为Web服务的操作。使用 @WebService 注解所标注的类被认为 Web 服务的端点,而使用 @WebMethod 注解所标注的方法被认为是操作。

就像大规模应用中的其他对象一样,JAX-WS 端点很可能需要与其他对象交互来完成工作。这意味着 JAX-WS 端点可以受益于依赖注入。但是如果端点的生命周期由 JAX-WS 运行时来管理,而不是由 Spring 来管理的话,这似乎不可能把 Spring 管理的 bean 装配进 JAX-WS 管理的端点实例中。

装配 JAX-WS 端点的秘密在于继承 SpringBeanAutowiringSupport。通过继承 SpringBeanAutowiringSupport,我们可以使用 @Autowired 注解标注端点的属性,依赖就会自动注入了。SpitterServiceEndpoint 展示了它是如何工作的。

package com.habuma.spittr.remoting.jaxws;

import java.util.List;
import javax.jws.WebMethod;
import javax.jws.WebService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
import com.habuma.spittr.domain.Spitter;
import com.habuma.spittr.domain.Spittle;
import com.habuma.spittr.service.SpitterService

@WebService(serviceName="SpitterService")
public class SpitterServiceEndpoint extends SpringBeanAutowiringSupport {
  @Autowired
  SpitterService spitterService;
  
  @WebMethod
  public void addSpittle(Spittle spittle) {
    spitterService.saveSpittle(spittle);
  }
  
  @WebMethod
  public void deleteSpittle(long spittleld) {
    spitterService.deleteSpittle(spittleld);
  }
  
  @WebMethod
  public List<Spittle> getRecentSpittles(int spittleCount) {
    return SpitterService.getRecentSpittles(spittleCount);
  }
  
  @WebMethod
  public List<Spittle> getSpittlesForSpitter(Spitter spitter) {
    return spitterService.getSpittlesForSpitter(spitter);
  }
}

我们在 SpitterService 属性上使用 @Autowired 注解来表明它应该自动注入一个从 Spring 应用上下文中所获取的 bean。在这里,端点委托注入的 SpitterService 来完成实际的工作。

导出独立的 JAX-WS 端点

正如我所说的,当对象的生命周期不是由 Spring 管理的,而对象的属性又需要注入 Spring 所管理的 bean 时,SpringBeanAutowiringSupport 很有用。在合适场景下, 还是可以把 Spring 管理的 bean 导出为 JAX-WS 端点的。

SpringSimpleJaxWsServiceExporter 的工作方式很类似于本章前边所介绍的其他服务导出器。它把 Spring 管理的 bean 发布为 JAX-WS 运行时中的服务端点。与其他服务导出器不同,SimpleJaxWsServiceExporter 不需要为它指定一个被导出 bean 的引用,它会将使用 JAX-WS 注解所标注的所有 bean 发布为 JAX-WS 服务。

SimpleJaxWsServiceExporter 可以使用如下的 @Bean 方法来配置:

@Bean
public SimpleJaxWsServiceExporter jaxWsExporter() {
  return new SimpleJaxWsServiceExporter();
}

正如我们所看到的,SimpleJaxWsServiceExporter 不需要再做其他的事情就可以完成所有的工作。当启动的时候,它会搜索 Spring 应用上下文来查找所有使用 @WebService 注解的 bean。当找到符合的 bean 时,SimpleJaxWsServiceExporter 使用 http://localhost:8080/ 地址将 bean 发布为 JAX-WS 端点。SpitterServiceEndpoint 就是其中一个被查找到的 bean。

程序清单 15.3 SimpleJaxWsServiceExporter 将 bean 转变为 JAX-WS 端点
package com.habuma.spittr.remoting.jaxws;

import java.util.List;
import javax.jws.WebMethod;
import javax.jws.WebService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.habuma.spittr.domain.Spitter;
import com.habuma.spittr.domain.Spittle;
import com.habuma.spittr.service.SpitterService;

@Component
@WebService(serviceName="SpitterService")
public class SpitterServiceEndpoint {
  @Autowired
  SpitterService SpitterService;
  
  @WebMethod
  public void addSpittle(Spittle spittle) {
    SpitterService.saveSpittle(spittle);
  }
  
  @WebMethod
  public void deleteSpittle(long spittleld) {
    spitterService.deleteSpittle(spittleld);
  )
  
  @WebMethod
  public List<Spittle> getRecentSpittles(int spittleCount) {
    return SpitterService.getRecentSpittles(spittleCount);
  }
  
  @WebMethod
  public List<Spittle> getSpittlesForSpitter(Spitter spitter) {
    return SpitterService.getSpittlesForSpitter(spitter);
  }
}

我们注意到 SpitterServiceEndpoint 的新实现不再继承 SpringBeanAutowiringSupport 了。它完全就是一个 Spring bean,因此 SpitterServiceEndpoint 不需要继承任何特殊的支持类就可以实现自动装配。

因为 SimpleJaxWsServiceEndpoint 的默认基本地址为 http://localhost:8080/,而 SpitterServiceEndpoint 使用了 @Webservice(servicename="SpitterService") 注解,所以这两个 bean 所形成的 Web 服务地址均为 http://localhost:8080/SpitterService。但是我们可以完全控制服务 URL,如果希望调整服务 URL 的话,我们可以调整基本地址。例如, 如下 SimpleJaxWsServiceEndpoint 的配置把相同的服务端点发布到http://localhost:8888/srvices/SpitterService

@Bean
public SimpleJaxWsServiceExporter jaxWsExporter() {
  SimpleJaxWsServiceExporter exporter = new SimpleJaxWsServiceExporter();
  exporter.setBaseAddress("http://localhost:8888/services/");
}

SimpleJaxWsServiceEndpoint 就像看起来那么简单,但是我们应该注意它只能用在支持将端点发布到指定地址的 JAX-WS 运行时中。这包含了 Sun 1.6 JDK 自带的 JAX-WS 运行时。其他的 JAX-WS 运行时,例如 JAX-WS 2.1 的参考实现,不支持这种类型的端点发布,因此也就不能使用 SimpleJaxWsServiceEndpoint。

Last updated