一、Spring Web Services 简介
Spring Web Services 是 Spring 提供的一个用于开发 SOAP Web 服务的框架。它强调契约优先(Contract-First)开发方式,支持 XML Schema、WSDL,适合需要与遗留系统或第三方集成的场景。
二、Spring WS 主要配置方式
Spring WS 支持两种主要配置方式:
- 基于 XML 配置(传统方式)
- 基于 Java 注解配置(推荐方式,Spring Boot 支持)
下面以 Spring Boot 为例,介绍基于注解的配置方式。
三、Spring WS 使用步骤
1. 添加依赖
如果你使用 Maven,添加如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
2. 定义 XML Schema (XSD)
在 src/main/resources 下创建一个 XSD 文件(如 countries.xsd),定义你的数据结构:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://example.com/ws/countries"
xmlns:tns="http://example.com/ws/countries"
elementFormDefault="qualified">
<xs:element name="getCountryRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="getCountryResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="country" type="tns:country"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="country">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="population" type="xs:int"/>
<xs:element name="capital" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
3. 使用 JAXB 生成 Java 类
可以用工具或 IDE 自动生成,也可以手动编写与 XSD 对应的 Java Bean。
例如:
@XmlRootElement(name = "getCountryRequest", namespace = "http://example.com/ws/countries")
public class GetCountryRequest {
private String name;
// getter/setter
}
4. 编写 Endpoint
Endpoint 是处理 SOAP 请求的核心类。
@Endpoint
public class CountryEndpoint {
private static final String NAMESPACE_URI = "http://example.com/ws/countries";
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
@ResponsePayload
public GetCountryResponse getCountry(@RequestPayload GetCountryRequest request) {
// 业务逻辑
GetCountryResponse response = new GetCountryResponse();
// 设置 response 内容
return response;
}
}
5. 配置 Web Service
创建一个配置类,注册 XSD Schema。
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
@Bean
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext context) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(context);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean<>(servlet, "/ws/*");
}
@Bean(name = "countries")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("CountriesPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace("http://example.com/ws/countries");
wsdl11Definition.setSchema(countriesSchema);
return wsdl11Definition;
}
@Bean
public XsdSchema countriesSchema() {
return new SimpleXsdSchema(new ClassPathResource("countries.xsd"));
}
}
6. 启动应用
启动 Spring Boot 应用后,访问 http://localhost:8080/ws/countries.wsdl 可获取 WSDL 文件。
四、常见进阶配置
1. 安全配置(WS-Security)
Spring WS 支持通过拦截器实现 SOAP 消息的安全性,例如用户名密码认证、签名等。
@Bean
public EndpointInterceptor securityInterceptor() {
Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor();
interceptor.setValidationActions("UsernameToken");
// 配置用户名、密码校验
return interceptor;
}
@Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
interceptors.add(securityInterceptor());
}
2. 日志与监控
可以通过拦截器或 Spring AOP 实现 SOAP 消息日志记录。
五、客户端调用
Spring WS 也支持客户端调用 SOAP 服务,常用 WebServiceTemplate:
@Autowired
private WebServiceTemplate webServiceTemplate;
GetCountryRequest request = new GetCountryRequest();
request.setName("China");
GetCountryResponse response = (GetCountryResponse) webServiceTemplate.marshalSendAndReceive(request);
六、参考资料
七、常见问题
- 端点没有被识别?
检查@Endpoint注解和@PayloadRoot的命名空间、localPart 是否正确。 - WSDL 无法访问?
检查 ServletMapping 是否正确,Bean 名必须和 WSDL 名一致。 - SOAP 消息格式不正确?
检查 JAXB 类和 XSD 是否匹配。
八、WS-Security 配置详解
Spring WS 支持基于 WS-Security 的 SOAP 消息安全。常见安全需求有:
- 用户名/密码认证
- 消息签名和加密
- 时间戳防重放
1. 添加依赖
除了 spring-boot-starter-web-services,还需要:
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-security</artifactId>
</dependency>
2. 配置 Wss4jSecurityInterceptor
@Bean
public Wss4jSecurityInterceptor securityInterceptor() {
Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor();
interceptor.setValidationActions("UsernameToken Timestamp");
interceptor.setValidationCallbackHandler(callbackHandler());
return interceptor;
}
@Bean
public CallbackHandler callbackHandler() {
SimplePasswordValidationCallbackHandler handler = new SimplePasswordValidationCallbackHandler();
Map<String, String> users = new HashMap<>();
users.put("admin", "password");
handler.setUsers(users);
return handler;
}
@Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
interceptors.add(securityInterceptor());
}
这样配置后,客户端必须在 SOAP Header 中携带用户名和密码。
九、拦截器与日志
1. 自定义 EndpointInterceptor
可以实现接口 EndpointInterceptor,在消息处理前后记录日志或做其他处理。
public class LoggingInterceptor implements EndpointInterceptor {
@Override
public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
// 记录请求日志
return true;
}
// 其他方法略
}
注册到配置类:
@Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
interceptors.add(new LoggingInterceptor());
}
十、异常处理
Spring WS 支持将 Java 异常转换为 SOAP Fault。
1. 使用 @SoapFault 注解
@Endpoint
public class CountryEndpoint {
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
@ResponsePayload
public GetCountryResponse getCountry(@RequestPayload GetCountryRequest request) throws CountryNotFoundException {
// 业务逻辑
throw new CountryNotFoundException("Country not found");
}
}
@SoapFault(faultCode = FaultCode.CLIENT)
public class CountryNotFoundException extends Exception {
public CountryNotFoundException(String message) { super(message); }
}
十一、复杂类型映射
JAXB 支持复杂对象、集合、嵌套对象等,只需在 XSD 中定义复杂类型,生成 Java 类即可。
例如:
<xs:complexType name="city">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="population" type="xs:int"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="country">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="cities" type="tns:city" maxOccurs="unbounded" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
生成 Java Bean:
@XmlType(name = "country")
public class Country {
private String name;
private List<City> cities;
// getter/setter
}
十二、单元测试与集成测试
1. Endpoint 单元测试
可以用 MockWebServiceClient 进行测试:
@RunWith(SpringRunner.class)
@SpringBootTest
public class CountryEndpointTest {
@Autowired
private ApplicationContext applicationContext;
private MockWebServiceClient client;
@Before
public void setup() {
client = MockWebServiceClient.createClient(applicationContext);
}
@Test
public void testGetCountry() throws Exception {
Source requestPayload = new StringSource(
"<getCountryRequest xmlns='http://example.com/ws/countries'><name>China</name></getCountryRequest>");
Source responsePayload = new StringSource(
"<getCountryResponse xmlns='http://example.com/ws/countries'><country><name>China</name></country></getCountryResponse>");
client.sendRequest(withPayload(requestPayload)).andExpect(payload(responsePayload));
}
}
十三、与 REST 风格的区别
| SOAP Web Service (Spring WS) | REST (Spring MVC) |
|---|---|
| 基于 XML、WSDL、XSD | 基于 HTTP/JSON |
| 强类型契约,易于跨语言集成 | 灵活,易于前后端分离 |
| 支持 WS-Security | 需自定义安全方案 |
| 适合企业、金融、遗留系统集成 | 适合轻量级服务 |
十四、常见问题与解决方案
- JAXB 版本冲突
检查依赖版本,Spring Boot 3.x 以上需要 Jakarta XML Binding。 - SOAP Header 处理
可以用@SoapHeader注解接收 Header 信息。 - WSDL 动态生成失败
检查 Bean 名和/ws/*映射是否一致。
十五、SOAP 附件处理(MTOM)
1. 什么是 MTOM?
MTOM(Message Transmission Optimization Mechanism)允许在 SOAP 消息中高效地传输二进制数据(如图片、文件),避免 base64 编码带来的性能损耗。
2. 服务端开启 MTOM
在 JAXB Bean 上添加注解:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ImageRequest {
@XmlMimeType("application/octet-stream")
protected DataHandler image;
// getter/setter
}
在端点方法参数和返回值中使用 DataHandler 类型。
3. 启用 MTOM 支持
在配置类中开启 MTOM:
@Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setPackagesToScan("com.example.ws.images");
marshaller.setMtomEnabled(true); // 关键
return marshaller;
}
客户端也需开启 MTOM:
WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
webServiceTemplate.setMarshaller(marshaller);
webServiceTemplate.setUnmarshaller(marshaller);
webServiceTemplate.setMtomEnabled(true);
十六、多端点服务管理
如果你有多个 SOAP 服务,可以为每个服务定义不同的 XSD、Endpoint、WSDL Bean:
@Bean(name = "orders")
public DefaultWsdl11Definition ordersWsdl(XsdSchema ordersSchema) { ... }
@Bean(name = "users")
public DefaultWsdl11Definition usersWsdl(XsdSchema usersSchema) { ... }
每个端点类通过不同的命名空间和 localPart 进行区分。
十七、WSDL 定制与版本管理
-
定制 WSDL
可以通过 DefaultWsdl11Definition 的各项属性定制端口名、服务名、命名空间等。 -
支持 WSDL 版本管理
可通过不同的 URL 暴露不同版本的 WSDL,例如/ws/v1/service.wsdl和/ws/v2/service.wsdl,分别对应不同的 XSD 和 Endpoint。
十八、性能优化建议
-
开启 Connection Pool
如果作为客户端调用,建议配置 HTTP 连接池。 -
使用 MTOM 处理大文件
避免 base64 传输,提升效率。 -
开启缓存
对静态 WSDL、XSD 文件开启缓存。 -
合理设置线程池
应用服务器端配置合理的线程池,提升并发处理能力。 -
启用 gzip 压缩
在 Tomcat/Nginx 层开启 gzip 压缩,降低网络带宽消耗。
二九、生产部署建议
-
使用 HTTPS
SOAP 服务通常涉及敏感数据,建议强制启用 HTTPS。 -
防止 XML 攻击
配置 XML 解析器防止 XXE、XML Bomb 等安全漏洞。 -
日志与监控
接入 ELK(Elasticsearch + Logstash + Kibana)、Prometheus 等监控平台,及时发现异常。 -
限流与熔断
在网关层或应用层做限流、熔断处理,防止服务被高并发压垮。
二十、常见集成场景
-
与第三方 SOAP 服务对接
使用 WebServiceTemplate,导入第三方 WSDL,自动生成客户端代码。 -
与企业 ESB 总线集成
Spring WS 支持标准 SOAP,可以与 IBM WebSphere、Oracle SOA Suite 等企业 ESB 平台无缝对接。 -
与 REST 服务桥接
可以在 Endpoint 内部调用 REST 服务,实现 SOAP-REST 转换,兼容新旧系统。
二十一、常见问题排查
| 问题 | 解决方法 |
|---|---|
| WSDL 无法访问或下载 | 检查 Bean 名与 URL 映射,Servlet 注册路径是否正确 |
| JAXB 类与 XSD 不匹配 | 检查 JAXB 类属性、注解与 XSD 元素是否一致 |
| SOAP Header 处理失败 | 检查 @SoapHeader 注解参数,或用拦截器处理 Header |
| MTOM 附件无法传输 | 检查 marshaller/unmarshaller 是否开启 MTOM |
| 客户端调用超时 | 配置 WebServiceTemplate 的超时时间参数 |
| 安全认证失败 | 检查 Wss4jSecurityInterceptor 配置、用户名密码是否正确 |
1万+

被折叠的 条评论
为什么被折叠?



