Spring Web Services 2.0 发布

工程 | Arjen Poutsma | 2011年1月11日 | ...

经过将近一年的开发,我很高兴地宣布 Spring Web Services 2.0 已经发布!在这篇文章中,我想回顾一些主要的新功能。

需要 Java 5+ 和 Spring 3.0

您可能已经知道,我们将对象 XML 映射 (OXM) 模块从 Spring-WS 项目移到了 Spring 3.0 中。因此,由于 org.springframework.oxm 包中存在冲突的类,使用 Spring-WS 1.5(带有自己的 OXM 模块)与 Spring 3.0 结合使用会有些问题。

从 2.0 版本开始,我们不再将 OXM 模块作为 Spring-WS 的一部分提供,而是依赖于 Spring 的 OXM。因此,**Spring Web Services 2.0 需要 Spring 3.0**才能工作。通常,我们倾向于对版本要求更宽松一些,不一定需要最新的 Spring 版本,但这是使事情正常工作的唯一方法。

由于依赖于 Spring 3.0,我们也**需要 Java 5+**,并且整个代码库都使用 Java 5 功能(例如泛型、可变参数和枚举),在有意义的地方使用它们。例如,与 XPathTemplate 结合使用的 NodeMapper 接口现在是泛型的,因此不再需要进行强制转换。


Person person = template.evaluateAsObject("//person", new DOMSource(document), new NodeMapper<Person>() {
    public Person mapNode(Node node, int nodeNum) throws DOMException {
        Element personElement = (Element) node;
        return new Person(personElement.getAttribute("firstName"), personElement.getAttribute("lastName"));
    }
});

请注意,即使我们确实升级了代码库以使用 Java 5+ 功能,我们也是以向后兼容的方式进行的。因此,**Spring Web Services 2.0 向后兼容 1.5**。但是,我们确实删除了已弃用的类。例如,XsdBasedSoap11Wsdl4jDefinitionBuilder 被放弃,取而代之的是 DefaultWsdl11Definition,它具有相同的功能,但更易于自定义。

改进的 @Endpoint 编程模型

Spring Web Services 2.0 中最重要的一个新功能是能够在 @Endpoint 方法中使用任意参数类型。对 Spring-WS 1.5 的 @Endpoint 模型的重大改进是,您现在可以混合匹配参数,并且在返回类型方面没有那么受限。基本上,这使 Spring-WS @Endpoint 编程模型与 Spring 3 的 @Controller 模型保持一致。

例如,您可以使用以下 @Endpoint 方法


@PayloadRoot(localPart = "myRequest", namespace = "http://example.com")
@ResponsePayload
public MyJaxb2Response handleMyRequest(@RequestPayload org.w3c.dom.Element myElement, 
                                       SoapHeader requestHeader,
                                       MessageContext messageContext) {

    // do something interesting here
}

此方法将接收任何 SOAP 消息,其中有效负载根元素具有“http://example.com”命名空间和“myRequest”本地名称。然后,此有效负载将与 SoapHeader(用于访问单个标头元素)和整个消息上下文一起作为 W3C DOM 元素传递。

当前支持的参数/返回类型包括

  • DOM 元素(默认情况下为 W3C DOM;如果类路径上存在 JDOM、dom4j、XOM,则会自动启用它们)
  • OXM Marshaller 支持的类型(需要显式配置的 marshaller)
  • 如果类路径上找到了 JAXB2,则为 JAXB2 类型(这意味着您不再需要显式配置 Jaxb2Marshaller)
  • javax.xml.transform.Source 和子类型
  • StAX XMLStreamReader 和 XMLEventreaders。请注意,这些只能用作参数类型,不能用作返回类型。

要将请求消息的有效负载作为任何这些参数类型获取,您必须使用 @RequestPayload 对参数进行注释。类似地,如果您希望返回值最终出现在响应消息的有效负载中,则必须使用 @ResponsePayload 对方法进行注释。这与 Spring 3 的 @Controller 模型非常相似,在该模型中,我们有 @RequestBody 和 @ResponseBody,它们在 HTTP 空间中提供类似的功能。

此外,我们支持以下无需 @RequestPayload 的参数类型

  • MessageContext
  • SoapHeader、SoapBody、SoapEvelope(请求消息的)
  • @XPathParam 参数。请注意,您现在可以使用 @Namespace 和 @Namespaces 注释指定 XPath 表达式中使用的任何命名空间,而不再需要在 XML 应用程序上下文中设置它们。例如
    
    @Namespaces(@Namespace(prefix = "tns", uri = "http://springframework.org/spring-ws"))
    public void myEndpointMethod(@XPathParam("/tns:root")String s) {
        // do something slightly more interesting here
    }
    

    这些命名空间注释(@Namespace 和 @Namespaces)可以存在于方法、类或包级别(即 package-info.java)。

要启用此编程模型,您只需将 <sws:annotation-driven/> 放入 Spring Web Services 应用程序上下文即可


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:sws="http://www.springframework.org/schema/web-services"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-2.0.xsd">

    <sws:annotation-driven/>

     <!-- other beans go here, or perhaps a <context:component-scan/> -->

</beans>

您可以选择为此元素提供 marshaller 和 unmarshaller 属性,分别指向 OXM Marshaller 和 Unmarshaller。这将启用对使用此 marshaller 支持的类型作为 @RequestPayload/@ResponsePayload 类型。

请注意,我们还弃用了对 <sws:marshalling-endpoints/> 和 <sws:xpath-endpoints/> 的支持,转而支持 <sws:annotation-driven/>。因此,这两个元素在 XSD 架构的 2.0 版本中不存在,但在 1.5 版本中仍然存在。因此,您可以坚持使用 1.5 版本的架构,或者升级到 2.0 和 <sws:annotation-driven/>。

最后,与 Spring 中的所有内容一样,参数/返回类型机制是完全可插拔的。因此,如果您没有看到您想看到的参数类型,请随时编写您自己的 MethodArgumentResolver 或 MethodReturnValueHandler,将其插入 Spring-WS,然后您就完成了!

新的集成测试模块

另一个主要的新功能是新的 Web 服务集成测试模块 spring-ws-test。此模块包含测试客户端(即使用 WebServiceTemplate 的类)和服务器(即 @Endpoints)的功能。客户端和服务器端测试模块都提供“流畅”的 API,因此您通常可以使用 IDE 中的代码完成功能(即 ctrl-space)来指导您完成设置测试的过程。

客户端集成测试

进行客户端集成测试的核心类是 MockWebServiceServer。其基本思想是 Web 服务模板连接到此模拟服务器,向其发送请求消息,然后模拟服务器根据已注册的期望验证该消息。如果满足期望,则模拟服务器会准备响应消息,并将其发送回模板。

测试客户端代码的典型方案包括

  1. 创建一个 MockWebServiceServer。
  2. 设置有关请求消息的期望。
  3. 创建一个适当的响应消息
  4. 像往常一样使用 WebServiceTemplate,可以直接使用或通过客户端代码使用。
  5. 调用 MockWebServiceServer.verify() 以确保已满足所有期望。

例如,考虑此 Web 服务客户端类


import org.springframework.ws.client.core.support.WebServiceGatewaySupport;

public class CustomerClient extends WebServiceGatewaySupport {                           

  public int getCustomerCount() {
    CustomerCountRequest request = new CustomerCountRequest();                           
    request.setCustomerName("John Doe");

    CustomerCountResponse response =
      (CustomerCountResponse) getWebServiceTemplate().marshalSendAndReceive(request);    
      
    return response.getCustomerCount();
  }
}

CustomerClient 的典型测试如下所示


import javax.xml.transform.Source;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.xml.transform.StringSource;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.assertEquals;

import org.springframework.ws.test.client.MockWebServiceServer;                          
import static org.springframework.ws.test.client.RequestMatchers.*;                      
import static org.springframework.ws.test.client.ResponseCreators.*;                     

@RunWith(SpringJUnit4ClassRunner.class)                                                  
@ContextConfiguration("integration-test.xml")                                            
public class CustomerClientIntegrationTest {

  @Autowired
  private CustomerClient client;                                                         

  private MockWebServiceServer mockServer;                                               

  @Before
  public void createServer() throws Exception {
    mockServer = MockWebServiceServer.createServer(client);
  }

  @Test
  public void customerClient() throws Exception {
    Source requestPayload = new StringSource(
      "<customerCountRequest xmlns='http://springframework.org/spring-ws'>" +
        "<customerName>John Doe</customerName>" +
      "</customerCountRequest>");
    Source responsePayload = new StringSource(
      "<customerCountResponse xmlns='http://springframework.org/spring-ws'>" +
        "<customerCount>10</customerCount>" +
      "</customerCountResponse>");

    mockServer.expect(payload(requestPayload)).andRespond(withPayload(responsePayload)); 

    int result = client.getCustomerCount();                                              
    assertEquals(10, result);                                                            

    mockServer.verify();                                                                 
  }
}

有关客户端测试的更多信息,请参阅参考手册

服务器端集成测试

进行服务器端集成测试的核心类是 MockWebServiceClient。其基本思想是,此客户端创建请求消息,然后将其发送到标准 MessageDispatcherServlet 应用程序上下文中配置的端点。这些端点将处理消息并创建响应。然后,客户端接收此响应并根据已注册的期望对其进行验证。

MockWebServiceClient 的典型用法是

  1. 创建一个 MockWebServiceClient 实例。
  2. 发送请求消息。
  3. 设置响应期望。

例如,考虑这个简单的 Web 服务端点类


@Endpoint                                                                                
public class CustomerEndpoint {

  @ResponsePayload                                                                       
  public CustomerCountResponse getCustomerCount(                                         
      @RequestPayload CustomerCountRequest request) {                                    
    CustomerCountResponse response = new CustomerCountResponse();
    response.setCustomerCount(10);
    return response;
  }
}

CustomerEndpoint 的典型测试如下所示


import javax.xml.transform.Source;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.xml.transform.StringSource;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.springframework.ws.test.server.MockWebServiceClient;                          
import static org.springframework.ws.test.server.RequestCreators.*;                      
import static org.springframework.ws.test.server.ResponseMatchers.*;                     

@RunWith(SpringJUnit4ClassRunner.class)                                                  
@ContextConfiguration("spring-ws-servlet.xml")                                           
public class CustomerEndpointIntegrationTest {

  @Autowired
  private ApplicationContext applicationContext;                                         

  private MockWebServiceClient mockClient;

  @Before
  public void createClient() {
    mockClient = MockWebServiceClient.createClient(applicationContext);                  
  }

  @Test
  public void customerEndpoint() throws Exception {
    Source requestPayload = new StringSource(
      "<customerCountRequest xmlns='http://springframework.org/spring-ws'>" +
        "<customerName>John Doe</customerName>" +
      "</customerCountRequest>");
    Source responsePayload = new StringSource(
      "<customerCountResponse xmlns='http://springframework.org/spring-ws'>" +
        "<customerCount>10</customerCount>" +
      "</customerCountResponse>");

    mockClient.sendRequest(withPayload(requestPayload)).                                 
      andExpect(payload(responsePayload));                                               
  }
}

有关服务器端测试的更多信息,请参阅参考手册

其他新功能

除了上面提到的主要功能外,还有其他一些功能
  • Spring Web Services 2.0 引入了对 Spring Security 3.0 的支持
  • 支持 XMPP(Jabber)传输

更多信息

如果您想试用 Spring Web Services 2.0,您可以访问站点,或直接访问下载。如果您使用 Maven,升级应该像添加以下存储库一样简单


<repository>
    <id>spring-release</id>
    <name>Spring Release Repository</name>
    <url>http://maven.springframework.org/release</url>
</repository>

然后可以像这样添加各个依赖项


<dependency>
    <groupId>org.springframework.ws</groupId>
    <artifactId>spring-ws-core</artifactId>
    <version>2.0.0.RELEASE</version>
</dependency>

这些 jar 文件很快就会在 Maven Central 上可用。

最后,我要感谢 Lukáš Křečan 和 Tareq Abed Rabbo。这两位社区成员在这个版本的开发过程中提供了很大的帮助。

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,以加速您的进步。

了解更多

获得支持

Tanzu Spring 在一个简单的订阅中提供对 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部