为什么在我的 CXF 和 Spring 配置中抛出异常现在展开 org.apache.cxf.interceptor.Fault

why in my CXF and Spring configuration throwning exception unwinding now org.apache.cxf.interceptor.Fault

我正在使用 CXF + Spring 公开 Soap Web 服务,当我通过 SoapUi 调用时,我得到

Application {http://art/}VmxServiceImplService#{http://art/}getV has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault

深入查看我的代码,我可以看到服务实现启动了两次:第一次我确实看到了可用的模拟,第二次我看到它为空。第一次对应于我部署应用程序并首次调用它。在这种情况下,setVmxMock 中的中断点清楚地显示 vmxMock 已填充。第二次和任何进一步的调用显示 vmxMock 为空。

我记得我在使用 Spring MVC 时遇到过类似的问题,但事实并非如此。在那种情况下,我通过更改 web.xml

来修复
<servlet-name>Servlet-plus-any-word</servlet-name>

不幸的是,同样的方法不适用于 CXFServlet。

我想问题是我缺少将 ContextLoaderListener 与 CXFServlet 分开的某些技巧,但我不知道该怎么做。所以,我的直截了当的问题是:我的 CXF 和 Spring 如此简单的 Web 服务设置有什么问题?

服务接口:

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
public interface VmxService {

    @WebMethod
    public VmxModel getV();

}

服务实施

//import javax.jws.WebService;

//@WebService(endpointInterface = "art.VmxService", serviceName = "vmxService")
public class VmxServiceImpl implements VmxService {

    private VmxMock vmxMock;

    public VmxServiceImpl() {
    }

    public void setVmxMock(VmxMock m) {
        this.vmxMock = m;
    }

    @Override
    public VmxModel getV() {
        return this.vmxMock.getVm();
    }

}

型号:

import java.io.Serializable;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "VmxModel")
public class VmxModel implements Serializable {

    private static final long serialVersionUID = 1L;

    private String retorno;

    public VmxModel() {
        System.out.println();

    }

    public String getRetorno() {
        return retorno;
    }

    public void setRetorno(String s) {
        retorno = s;
    }
}

模拟

public class VmxMock {

    VmxModel vm = new VmxModel();

    public VmxMock(){
        this.vm.setRetorno("retorno");
    }

    public VmxModel getVm(){
        return vm;
    }

}

spring-beans.xml

<?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="
 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">


    <import resource="classpath:META-INF/cxf/cxf.xml" />

    <bean id="vmxMock" class="art.VmxMock" />

    <bean id="vmxServiceImpl" class="art.VmxServiceImpl">
        <property name="vmxMock">
            <ref bean="vmxMock" />
        </property>
    </bean>

    <jaxws:endpoint id="vmxService" implementor="art.VmxServiceImpl"
        address="/VmxService" />

</beans>

web.xml(大概错误根源在这里)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
    <display-name>art</display-name>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-beans.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <servlet>
        <description>CXF Servlet</description>
        <servlet-name>CXFServlet</servlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

Pom:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>grp</groupId>
    <artifactId>art</artifactId>
    <packaging>war</packaging>

    <version>0.0.1-SNAPSHOT</version>
    <name>art Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <properties>
        <jdk.version>1.8</jdk.version>
        <cxf.version>3.1.8</cxf.version>
        <spring.version>4.3.4.RELEASE</spring.version>
        <!-- <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> -->
    </properties>

    <dependencies>
        <!-- Spring dependencies -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- Apache cxf dependencies -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <!-- servlet & jsp -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.1.2</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>art</finalName>
        <!-- <pluginManagement> -->

            <plugins>

                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.2</version>
                    <configuration>
                        <source>${jdk.version}</source>
                        <target>${jdk.version}</target>
                    </configuration>
                </plugin>

                <plugin>
                    <groupId>org.apache.cxf</groupId>
                    <artifactId>cxf-java2ws-plugin</artifactId>
                    <version>${cxf.version}</version>
                    <executions>
                        <execution>
                            <id>process-classes</id>
                            <phase>process-classes</phase>
                            <configuration>

                                <className>art.VmxService</className>

                                <outputFile>${project.basedir}/src/main/resources/VmxService.wsdl</outputFile>
                                <genWsdl>true</genWsdl>
                                <verbose>true</verbose>

                                <address>http://localhost:9080/art/VmxService</address>
                            </configuration>
                            <goals>
                                <goal>java2ws</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>

            </plugins>
<!--        </pluginManagement> -->
    </build>
</project>

WebSphere Liberty Profile 控制台错误

[05/12/16 19:09:22:593 BRST] 00000172 org.apache.cxf.phase.PhaseInterceptorChain                   W Application {http://art/}VmxServiceImplService#{http://art/}getV has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault
    at org.apache.cxf.service.invoker.AbstractInvoker.createFault(AbstractInvoker.java:162)
    at org.apache.cxf.jaxws.AbstractJAXWSMethodInvoker.createFault(AbstractJAXWSMethodInvoker.java:267)
    at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:128)
    at org.apache.cxf.jaxws.AbstractJAXWSMethodInvoker.invoke(AbstractJAXWSMethodInvoker.java:232)
    at org.apache.cxf.jaxws.JAXWSMethodInvoker.invoke(JAXWSMethodInvoker.java:85)
    at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:74)
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor.run(ServiceInvokerInterceptor.java:59)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor.run(ServiceInvokerInterceptor.java:126)
    at org.apache.cxf.workqueue.SynchronousExecutor.execute(SynchronousExecutor.java:37)
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:131)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
    at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
    at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:252)
    at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234)
    at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208)
    at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160)
    at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:180)
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:299)
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:218)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:274)
    at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1290)
    at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:778)
    at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:475)
    at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1161)
    at com.ibm.ws.webcontainer.servlet.CacheServletWrapper.handleRequest(CacheServletWrapper.java:82)
    at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:938)
    at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost.run(DynamicVirtualHost.java:278)
    at com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink$TaskWrapper.run(HttpDispatcherLink.java:967)
    at com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink.wrapHandlerAndExecute(HttpDispatcherLink.java:359)
    at com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink.ready(HttpDispatcherLink.java:318)
    at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:471)
    at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.handleNewRequest(HttpInboundLink.java:405)
    at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.processRequest(HttpInboundLink.java:285)
    at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.ready(HttpInboundLink.java:256)
    at com.ibm.ws.tcpchannel.internal.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:174)
    at com.ibm.ws.tcpchannel.internal.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:83)
    at com.ibm.ws.tcpchannel.internal.WorkQueueManager.requestComplete(WorkQueueManager.java:504)
    at com.ibm.ws.tcpchannel.internal.WorkQueueManager.attemptIO(WorkQueueManager.java:574)
    at com.ibm.ws.tcpchannel.internal.WorkQueueManager.workerRun(WorkQueueManager.java:929)
    at com.ibm.ws.tcpchannel.internal.WorkQueueManager$Worker.run(WorkQueueManager.java:1018)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
    at art.VmxServiceImpl.getV(VmxServiceImpl.java:25)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:180)
    at org.apache.cxf.jaxws.JAXWSMethodInvoker.performInvocation(JAXWSMethodInvoker.java:66)
    at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:96)
    ... 43 more

改变

<jaxws:endpoint id="vmxService" implementor="art.VmxServiceImpl" address="/VmxService" />

<jaxws:endpoint id="vmxService" implementor="#vmxServiceImpl" address="/VmxService" />

您提供的是 class 名称,而不是参考。请参阅 JAX-WS configuration 中对 implementor 属性的描述。

The implementor of jaxws endpoint. You can specify the implementor class name here, or just the ref bean name in the format of "#REF_BEAN_NAME"

因此,CXF 在启动 jax-ws 端点时会创建 art.VmxServiceImpl 的新实例。在这个新实例中,vmxMock 为空且

return this.vmxMock.getVm();

导致堆栈跟踪的主要错误

Caused by: java.lang.NullPointerException
    at art.VmxServiceImpl.getV(VmxServiceImpl.java:25)