Skip to content

Spring Integration Web Services 支持教程

概述

本教程将介绍 Spring Integration 对 Web Services 的支持,包括入站/出站网关配置、消息处理等核心功能。采用现代 Spring 最佳实践,优先使用注解和 Kotlin DSL,避免 XML 配置。

kotlin
// 添加必要依赖 (build.gradle.kts)
dependencies {
    implementation("org.springframework.integration:spring-integration-ws:6.5.1")
}

一、核心概念

1.1 Web Services 网关类型

网关类型作用适用场景
入站网关接收外部 Web 服务请求创建服务端点
出站网关调用外部 Web 服务服务消费
编组网关处理对象-XML 转换复杂数据结构处理

类比理解

将网关视为邮局:

  • 入站网关 = 接收邮件的信箱
  • 出站网关 = 寄出邮件的邮筒
  • 编组网关 = 翻译国际信件的专员

二、出站网关配置

2.1 基础出站网关

kotlin
@Configuration
class WsOutboundConfig {

    @Bean
    fun simpleOutboundGateway(): IntegrationFlow {
        return IntegrationFlow.from("requestChannel")
            .handle(
                Ws.simpleOutboundGateway("https://api.example.com/service")
                    .id("simpleGateway")
            )
            .get()
    }
}

2.2 编排出站网关 (处理对象-XML转换)

kotlin
@Bean
fun marshallingOutboundGateway(marshaller: Marshaller): IntegrationFlow {
    return IntegrationFlow.from("marshallingChannel")
        .handle(
            Ws.marshallingOutboundGateway("https://api.example.com/data")
                .marshaller(marshaller)
                .unmarshaller(marshaller) 
                .headerMapper(SoapHeaderMapper()) 
        )
        .get()
}

TIP

最佳实践建议

  • 使用 WebServiceTemplate 复用连接资源
  • 对动态 URI 使用 DestinationProvider
  • 设置超时:.setReplyTimeout(Duration.ofSeconds(30))

三、入站网关配置

3.1 基础入站网关

kotlin
@Bean
fun simpleInboundGateway(): IntegrationFlow {
    return IntegrationFlow.from(
        Ws.simpleInboundGateway()
            .id("inboundGateway")
    )
    .channel("processingChannel")
    .get()
}

3.2 编排入站网关

kotlin
@Bean
fun marshallingInboundGateway(marshaller: Marshaller): IntegrationFlow {
    return IntegrationFlow.from(
        Ws.marshallingInboundGateway(marshaller)
            .extractPayload(false)  // 获取完整消息
    )
    .transform { payload: Source ->
        // 自定义XML处理逻辑
        extractDataFromSource(payload)
    }
    .get()
}

重要注意事项

入站网关必须注册到 Spring WS 端点映射:

kotlin
@Bean
fun endpointMapping(): SimpleMethodEndpointMapping {
    val mapping = SimpleMethodEndpointMapping()
    mapping.endpoints = setOf(marshallingInboundGateway())
    return mapping
}

四、高级配置技巧

4.1 动态 URI 配置

kotlin
@Bean
fun dynamicUriGateway(registry: ServiceRegistry): IntegrationFlow {
    return IntegrationFlow.from("dynamicChannel")
        .handle(
            Ws.simpleOutboundGateway()
                .destinationProvider { 
                    registry.getServiceUri("targetService")
                }
                .encodingMode(DefaultUriBuilderFactory.EncodingMode.NONE)
        )
        .get()
}

4.2 自定义头部处理

kotlin
class CustomSoapHeaderMapper : DefaultSoapHeaderMapper() {

    init {
        // 映射自定义头部
        setRequestHeaderNames("STANDARD_REQUEST_HEADERS", "custom*")
        setReplyHeaderNames("STANDARD_REPLY_HEADERS", "!internal*")
    }

    override fun fromSoapHeaders(headers: SoapHeaders): Map<String, Any> {
        val map = super.fromSoapHeaders(headers)
        // 添加自定义处理逻辑
        map["processedAt"] = Instant.now()
        return map
    }
}

CAUTION

安全警告: 当处理 X-Forwarded-* 头部时,务必验证来源 IP,防止头部注入攻击


五、MTOM 附件支持

kotlin
@Bean
fun mtomInboundGateway(): IntegrationFlow {
    return IntegrationFlow.from(
        Ws.marshallingInboundGateway(jaxbMarshaller())
            .messageFactory(soapMessageFactory()) 
    )
    .enrichHeaders { 
        it.header("attachments", 
            { message -> 
                (message.payload as SoapMessage).attachments
            }
        )
    }
    .get()
}

@Bean
fun soapMessageFactory(): SaajSoapMessageFactory {
    val factory = SaajSoapMessageFactory(MessageFactory.newInstance())
    factory.isMtomEnabled = true
    return factory
}
MTOM 附件发送示例
kotlin
fun sendWithAttachment(payload: Any, attachment: Resource) {
    webServiceTemplate.send { message: WebServiceMessage ->
        val soapMessage = message as SoapMessage
        // 添加XML负载
        marshaller.marshal(payload, soapMessage.payloadResult)
        // 添加附件
        soapMessage.addAttachment("doc1", 
            InputStreamResource(attachment.inputStream),
            "application/pdf"
        )
    }
}

六、常见问题解决

问题1:空响应处理

症状:出站网关未收到响应消息

解决方案

kotlin
Ws.simpleOutboundGateway(uri)
    .ignoreEmptyResponses(false) 

问题2:URI 编码错误

症状:特殊字符被错误编码

解决方案

kotlin
.destinationProvider {
    "https://example.com/path?param=${URLEncoder.encode(value, "UTF-8")}"
}
.encodingMode(DefaultUriBuilderFactory.EncodingMode.NONE)

问题3:头部丢失

症状:自定义SOAP头部未被传递

检查点

  1. 确认 headerMapper 配置了正确的头部模式
  2. 验证头部名称未被排除(如使用 !internal*
  3. 检查是否超过最大头部大小限制

总结

Spring Integration 的 Web Services 支持提供了:

  1. 声明式配置:通过 Kotlin DSL 简化网关设置
  2. ⚡️ 灵活的消息转换:支持对象-XML自动编组
  3. 🔒 企业级特性:MTOM附件、头部映射、URI控制

IMPORTANT

生产环境建议

  • 为所有出站调用添加熔断机制
  • 使用 WebServiceTemplate 连接池
  • 启用 SOAP 消息日志记录
  • 对动态 URI 实现速率限制