CXF与Spring集成问题:JAX-RS服务Bean的Autowired注入失败
Hey there, let's tackle your CXF + Spring issue step by step. I've dealt with this exact scenario before, so here's what you need to know:
CXF is deeply integrated with Spring—think of it as a communication layer that leverages Spring's IoC container for managing bean lifecycles and dependencies. Here's the core flow:
- You define your service/controller classes as Spring-managed beans
- CXF uses Spring's container to fetch these beans when setting up endpoints
- CXF handles the SOAP/REST communication logic, while Spring takes care of creating your beans, injecting their dependencies, and managing their lifecycle.
In short: Spring owns the beans, CXF uses them to handle web service requests.
The root cause of your startup failure is simple: when CXF tries to instantiate your controller directly (without Spring's help), it looks for a no-argument default constructor—which you don't have anymore because you added a constructor with parameters.
The solution is to let Spring handle instantiating your controller (with constructor injection) first, then have CXF reference the pre-configured bean. Here are two concrete approaches:
Option 1: XML Configuration (Since You're Using beans.xml)
Suppose your controller class looks like this:
public class TestController { private final SomeDependency myDependency; // Only constructor—no default no-arg constructor public TestController(SomeDependency myDependency) { this.myDependency = myDependency; } // Your web service methods here public String getGreeting() { return "Hello from " + myDependency.getServiceName(); } }
Update your beans.xml to explicitly define the controller bean with constructor arguments, then have CXF reference that bean instead of instantiating it directly:
<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="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <!-- 1. Define your dependency bean first --> <bean id="someDependency" class="com.yourpackage.SomeDependency"/> <!-- 2. Define your controller with constructor injection --> <bean id="testController" class="com.yourpackage.TestController"> <!-- Reference the dependency bean for the constructor parameter --> <constructor-arg ref="someDependency"/> <!-- For primitive values, use <constructor-arg value="your-value"/> instead --> </bean> <!-- 3. Configure CXF endpoint to use the pre-built Spring bean --> <jaxws:endpoint id="testService" implementor="#testController" address="/TestService"/> </beans>
Key note: Use #testController (the bean ID) in the implementor attribute instead of the full class name. This tells CXF to fetch the already-instantiated bean from Spring's container, instead of trying to create it itself.
Option 2: Annotation-Driven Injection (If Your Project Supports It)
If you're using Spring's annotation support, you can simplify this by letting Spring auto-wire the constructor. First, mark your controller as a Spring component and annotate the constructor:
import org.springframework.stereotype.Component; import org.springframework.beans.factory.annotation.Autowired; @Component // Tells Spring to manage this bean public class TestController { private final SomeDependency myDependency; // Spring 4.3+ doesn't require @Autowired if this is the only constructor @Autowired public TestController(SomeDependency myDependency) { this.myDependency = myDependency; } // Web service methods... }
Then update beans.xml to enable component scanning and have CXF reference the controller class (Spring will already have instantiated it):
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- Enable Spring's component scanning to find your @Component beans --> <context:component-scan base-package="com.yourpackage"/> <!-- CXF endpoint can now reference the class directly (Spring has it ready) --> <jaxws:endpoint id="testService" implementor="com.yourpackage.TestController" address="/TestService"/> </beans>
- Always let Spring handle instantiating your service/controller beans (with constructor injection)
- Never let CXF instantiate the class directly—reference the Spring-managed bean instead
- This aligns with how CXF and Spring are designed to work together, and solves the "missing default constructor" error immediately.
内容的提问来源于stack exchange,提问作者Neok

