During our recent upgrade from Spring 3 to Spring 6 while using CXF 4, we encountered a perplexing issue:
SOAP 1.1 endpoint already registered on address /soap/xxxService
Root Cause
We discovered that Spring 6's enhanced bean lifecycle management conflicts with CXF's endpoint registration mechanism. Here's what happens:
1. Spring 6 Configuration Loading Changes
Spring 6 introduced stricter bean definition and lifecycle management, which can cause CXF endpoints to be registered multiple times through different mechanisms:
// Multiple registration paths:
// 1. Auto-discovery via @WebService annotations
// 2. Explicit XML configuration
// 3. Java-based configuration
// 4. CXF's internal auto-configuration
2. The Duplicate Registration Scenario
Without proper CXF initialization, endpoints get registered multiple times:
<!-- XML Configuration -->
<jaxws:endpoint id="xxxService"
implementor="#xxxServiceImpl"
address="/soap/xxxService" />
<!-- Component Scanning might also pick up the same service -->
<context:component-scan base-package="com.example.service" />
3. Missing CXF Core Configuration
Spring 6 no longer automatically loads certain CXF configurations that were previously handled implicitly, leading to an improperly initialized CXF Bus and DestinationRegistry.
Why Importing CXF Configuration Files Solves the Issue
The Role of cxf.xml
The META-INF/cxf/cxf.xml
file contains essential CXF infrastructure beans:
<beans xmlns="http://www.springframework.org/schema/beans"...>
<!-- CXF Bus - the core of CXF -->
<bean id="cxf" class="org.apache.cxf.bus.spring.SpringBus" destroy-method="shutdown">
<!-- ... -->
</bean>
<!-- Ensures Bus singleton pattern -->
<bean id="org.apache.cxf.bus.spring.BusWiringBeanFactoryPostProcessor"
class="org.apache.cxf.bus.spring.BusWiringBeanFactoryPostProcessor">
<!-- ... -->
</bean>
</beans>
Solution
Add the imports to your Spring configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="...">
<!-- Import CXF core configurations -->
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<!-- Your endpoint definitions -->
<jaxws:endpoint id="xxxService"
implementor="com.example.service.XxxServiceImpl"
address="/soap/xxxService">
<jaxws:properties>
<entry key="schema-validation-enabled" value="true"/>
</jaxws:properties>
</jaxws:endpoint>
</beans>
The imported configurations guarantee that only one CXF Bus is created and properly initialized. The DestinationRegistry from cxf-servlet.xml
maintains a single registry of all endpoints Explicit configuration takes precedence over any auto-discovery mechanisms.
Top comments (0)