Spring WS定义两个同命名空间同localPart的Endpoint时出现映射冲突错误
解决Spring WS相同@PayloadRoot端点冲突并按路径区分的问题
你的思路方向是对的——通过隔离ApplicationContext来避免全局端点映射冲突,但之前的配置缺少了Spring WS运行必需的核心组件,导致端点无法被正确识别。下面是完整的修正方案,无需修改WSDL定义:
问题根源
Spring WS默认会把所有@Endpoint注册到全局的端点映射器中,相同的@PayloadRoot(命名空间+localPart)会直接触发冲突。而你之前的子ApplicationContext只注册了Endpoint,没有配置Spring WS的核心基础设施(比如WSDL定义、端点映射规则),所以MessageDispatcherServlet找不到对应的端点处理请求。
正确配置步骤
1. 为每个端点创建独立的Spring WS配置类
每个配置类单独启用@EnableWs,并注册对应的Endpoint、WSDL定义和Schema,确保每个上下文拥有完整的WS运行环境:
对应EndpointA的配置类
@EnableWs @Configuration public class WebServiceConfigA { // 注册WSDL定义,保持和原WSDL一致的命名空间 @Bean public DefaultWsdl11Definition defaultWsdl11DefinitionA(XsdSchema exampleSchema) { DefaultWsdl11Definition wsdlDefinition = new DefaultWsdl11Definition(); wsdlDefinition.setPortTypeName("ExamplePortA"); // 端口名可以区分,但不影响WSDL核心定义 wsdlDefinition.setLocationUri("/clientA/services"); // 对应Servlet路径 wsdlDefinition.setTargetNamespace("http://example.com"); // 和原WSDL命名空间一致 wsdlDefinition.setSchema(exampleSchema); return wsdlDefinition; } // 加载原有的XSD Schema文件 @Bean public XsdSchema exampleSchema() { return new SimpleXsdSchema(new ClassPathResource("your-schema-file.xsd")); } // 注册EndpointA @Bean public EndpointA endpointA() { return new EndpointA(); } }
对应EndpointB的配置类
@EnableWs @Configuration public class WebServiceConfigB { @Bean public DefaultWsdl11Definition defaultWsdl11DefinitionB(XsdSchema exampleSchema) { DefaultWsdl11Definition wsdlDefinition = new DefaultWsdl11Definition(); wsdlDefinition.setPortTypeName("ExamplePortB"); wsdlDefinition.setLocationUri("/clientB/services"); wsdlDefinition.setTargetNamespace("http://example.com"); wsdlDefinition.setSchema(exampleSchema); return wsdlDefinition; } @Bean public XsdSchema exampleSchema() { return new SimpleXsdSchema(new ClassPathResource("your-schema-file.xsd")); } @Bean public EndpointB endpointB() { return new EndpointB(); } }
2. 主配置类创建独立的Servlet上下文
移除原有的WsConfigurationSupport继承,为每个Endpoint创建独立的MessageDispatcherServlet,并绑定对应的子配置类:
@Configuration public class WebServiceConfig { @Bean public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServletA() { AnnotationConfigWebApplicationContext ctxA = new AnnotationConfigWebApplicationContext(); ctxA.register(WebServiceConfigA.class); MessageDispatcherServlet servletA = new MessageDispatcherServlet(ctxA); servletA.setTransformWsdlLocations(true); return new ServletRegistrationBean<>(servletA, "/clientA/services/*"); } @Bean public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServletB() { AnnotationConfigWebApplicationContext ctxB = new AnnotationConfigWebApplicationContext(); ctxB.register(WebServiceConfigB.class); MessageDispatcherServlet servletB = new MessageDispatcherServlet(ctxB); servletB.setTransformWsdlLocations(true); return new ServletRegistrationBean<>(servletB, "/clientB/services/*"); } }
3. 启动类排除全局扫描
确保主ApplicationContext不会扫描这两个Endpoint和配置类,避免全局冲突:
@ComponentScan(basePackages = "com.example", excludeFilters = { @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = { EndpointA.class, EndpointB.class, WebServiceConfigA.class, WebServiceConfigB.class }) }) @SpringBootApplication public class ExampleApplication { public static void main(String[] args) { SpringApplication.run(ExampleApplication.class, args); } }
验证方式
启动应用后,分别访问两个路径的WSDL:
http://localhost:8080/clientA/services/example.wsdlhttp://localhost:8080/clientB/services/example.wsdl
两个WSDL的核心定义和原文件一致,但对应不同的访问路径。调用sendSomething接口时,请求/clientA/services/*会触发EndpointA的逻辑,请求/clientB/services/*会触发EndpointB的逻辑。
内容的提问来源于stack exchange,提问作者Marco Domenicano
相关产品推荐
相关产品推荐

