'没有端点适配器'例外 - 带有spring-boot和spring-ws的apache-camel

Mat*_*lls 3 spring web-services spring-ws apache-camel spring-boot

JVM 1.8.0_45
apache-camel 2.15.2
spring-ws 2.2.1
spring-boot 1.2.4

我试图在spring-boot应用程序中使用apache-camel(2.15.2)来处理传入的Web服务调用.

我根据这里的指南创建了一个初始工作的春季启动项目(没有骆驼)http://spring.io/guides/gs/producing-web-service/

然后我尝试将Camel:Spring Web Services组件集成为Consumer来处理传入的Web服务请求,遵循"公开Web服务"部分中的指导原则http://camel.apache.org/spring-web-services.html

WebServiceConfig.java

import org.apache.camel.component.spring.ws.bean.CamelEndpointMapping;

@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {

    @Bean
    public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
        MessageDispatcherServlet servlet = new MessageDispatcherServlet();
        servlet.setApplicationContext(applicationContext);
        servlet.setTransformWsdlLocations(true);
        return new ServletRegistrationBean(servlet, "/ws/*");
    }

    // default wsdl stuff here...

    // exposing the endpoint mapping bean here rather than in spring-ws-servlet.xml (seems to work)
    @Bean  public CamelEndpointMapping  endpointMapping() {
        return new CamelEndpointMapping();
    }
}
Run Code Online (Sandbox Code Playgroud)

ClaimRouter.java

import org.apache.camel.LoggingLevel;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.model.dataformat.JaxbDataFormat;
import org.springframework.stereotype.Component;

@Component
public class ClaimRouter extends RouteBuilder {

    @Override
    public void configure() throws Exception {

        JaxbDataFormat jaxb = new JaxbDataFormat(false);
        jaxb.setContextPath("uk.co.example.claim.ws.v2"); 

        // comment @PayloadRoot annotation in ClaimEndpointV2.java to enable requests to be mapped to this camel route
        from("spring-ws:rootqname:{http://example.co.uk/claim/ws/v2}getClaimRequest?endpointMapping=#endpointMapping")
        .to("log:uk.co.example.claim.ws.v2?level=INFO")
        .unmarshal(jaxb)
        .process(new ClaimProcessor())
        .marshal(jaxb);
    }
}
Run Code Online (Sandbox Code Playgroud)

根据日志(如下),传入的请求已成功映射到我的Camel Consumer,但随后失败并显示"No adapter for endpoint"

[2015-06-24 13:22:03.981] boot - 6892 DEBUG [http-nio-8090-exec-6] --- WsdlDefinitionHandlerAdapter: Transforming [/ws] to [http://localhost:8090/ws]
[2015-06-24 13:22:03.983] boot - 6892 DEBUG [http-nio-8090-exec-6] --- MessageDispatcherServlet: Successfully completed request
[2015-06-24 13:22:13.544] boot - 6892 DEBUG [http-nio-8090-exec-7] --- WebServiceMessageReceiverHandlerAdapter: Accepting incoming [org.springframework.ws.transport.http.HttpServletConnection@70863933] at [http://localhost:8090/ws]
[2015-06-24 13:22:13.547] boot - 6892 DEBUG [http-nio-8090-exec-7] --- received: Received request [SaajSoapMessage {http://example.co.uk/claim/ws/v2}getClaimRequest]
[2015-06-24 13:22:13.547] boot - 6892 DEBUG [http-nio-8090-exec-7] --- PayloadRootAnnotationMethodEndpointMapping: Looking up endpoint for [{http://example.co.uk/claim/ws/v2}getClaimRequest]
[2015-06-24 13:22:13.547] boot - 6892 DEBUG [http-nio-8090-exec-7] --- SoapMessageDispatcher: Endpoint mapping [org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping@5fdbde50] has no mapping for request
[2015-06-24 13:22:13.547] boot - 6892 DEBUG [http-nio-8090-exec-7] --- SoapActionAnnotationMethodEndpointMapping: Looking up endpoint for []
[2015-06-24 13:22:13.547] boot - 6892 DEBUG [http-nio-8090-exec-7] --- SoapMessageDispatcher: Endpoint mapping [org.springframework.ws.soap.server.endpoint.mapping.SoapActionAnnotationMethodEndpointMapping@50bf4dcb] has no mapping for request
[2015-06-24 13:22:13.547] boot - 6892 DEBUG [http-nio-8090-exec-7] --- SoapMessageDispatcher: Endpoint mapping [org.springframework.ws.soap.addressing.server.AnnotationActionEndpointMapping@8b5028a] has no mapping for request
[2015-06-24 13:22:13.548] boot - 6892 DEBUG [http-nio-8090-exec-7] --- SoapMessageDispatcher: Endpoint mapping [org.apache.camel.component.spring.ws.bean.CamelEndpointMapping@7a9ff5b1] maps request to endpoint [Consumer[spring-ws://rootqname:(http://example.co.uk/claim/ws/v2)getClaimRequest?endpointMapping=%23endpointMapping]]
[2015-06-24 13:22:13.548] boot - 6892 DEBUG [http-nio-8090-exec-7] --- SoapMessageDispatcher: Testing endpoint adapter [org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter@5a1e093a]
[2015-06-24 13:22:13.549] boot - 6892 DEBUG [http-nio-8090-exec-7] --- SoapFaultAnnotationExceptionResolver: Resolving exception from endpoint [Consumer[spring-ws://rootqname:(http://example.co.uk/claim/ws/v2)getClaimRequest?endpointMapping=%23endpointMapping]]: java.lang.IllegalStateException: No adapter for endpoint [Consumer[spring-ws://rootqname:(http://example.co.uk/claim/ws/v2)getClaimRequest?endpointMapping=%23endpointMapping]]: Is your endpoint annotated with @Endpoint, or does it implement a supported interface like MessageHandler or PayloadEndpoint?
[2015-06-24 13:22:13.549] boot - 6892 DEBUG [http-nio-8090-exec-7] --- SimpleSoapExceptionResolver: Resolving exception from endpoint [Consumer[spring-ws://rootqname:(http://example.co.uk/claim/ws/v2)getClaimRequest?endpointMapping=%23endpointMapping]]: java.lang.IllegalStateException: No adapter for endpoint [Consumer[spring-ws://rootqname:(http://example.co.uk/claim/ws/v2)getClaimRequest?endpointMapping=%23endpointMapping]]: Is your endpoint annotated with @Endpoint, or does it implement a supported interface like MessageHandler or PayloadEndpoint?
[2015-06-24 13:22:13.549] boot - 6892 DEBUG [http-nio-8090-exec-7] --- SoapMessageDispatcher: Endpoint invocation resulted in exception - responding with Fault
java.lang.IllegalStateException: No adapter for endpoint [Consumer[spring-ws://rootqname:(http://example.co.uk/claim/ws/v2)getClaimRequest?endpointMapping=%23endpointMapping]]: Is your endpoint annotated with @Endpoint, or does it implement a supported interface like MessageHandler or PayloadEndpoint?
        at org.springframework.ws.server.MessageDispatcher.getEndpointAdapter(MessageDispatcher.java:302)
        at org.springframework.ws.server.MessageDispatcher.dispatch(MessageDispatcher.java:235)
        at org.springframework.ws.server.MessageDispatcher.reessageDispatcher.java:176)
        at org.springframework.ws.transport.support.WebServiceMessageReceiverObjectSupport.handleConnection(WebServiceMessageReceiverObjectSupport.java:89)
        at org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter.handle(WebServiceMessageReceiverHandlerAdapter.java:61)
        at org.springframework.ws.transport.http.MessageDispatcherServlet.doService(MessageDispatcherServlet.java:293)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
        at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
        at org.apache.catali.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1521)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1478)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)
[2015-06-24 13:22:13.554] boot - 6892 DEBUG [http-nio-8090-exec-7] --- sent: Sent response [SaajSoapMessage {http://schemas.xmlsoap.org/soap/envelope/}Fault] for request [SaajSoapMessage {http://example.co.uk/claim/ws/v2}getClaimRequest]
[2015-06-24 13:22:13.556] boot - 6892 DEBUG [http-nio-8090-exec-7] --- MessageDispatcherServlet: Successfully completed request
Run Code Online (Sandbox Code Playgroud)

我的gradle依赖项如下:

dependencies {
    compile("org.springframework.boot:spring-boot-starter-ws") {
        exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
    }
    compile("org.springframework.boot:spring-boot-starter") {
        exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
    }
    compile("org.springframework.boot:spring-boot-starter-log4j")
    compile("org.springframework:spring-web")
    compile("com.fasterxml.jackson.core:jackson-databind")
    compile("org.apache.camel:camel-core:2.15.2")
    compile("org.apache.camel:camel-spring-boot:2.15.2")
    compile("org.apache.camel:camel-spring-ws:2.15.2")
    compile("org.apache.camel:camel-jaxb:2.15.2")
    testCompile("org.springframework.boot:spring-boot-starter-test")
    compile 'org.slf4j:slf4j-log4j12:1.7.12'
    compile("wsdl4j:wsdl4j:1.6.1")
    jaxb("com.sun.xml.bind:jaxb-xjc:2.2.4-1")
    compile sourceSets.generated.output
}
Run Code Online (Sandbox Code Playgroud)

我研究了很多针对端点问题的无适配器,其中大多数似乎都是由端点的返回类型引起的.但是,我只是创建了一个camel路由,所以假设camel-spring-ws集成应该提供实际的端点.

我是否错过了一个关键的配置/注释或者是否存在更基本的问题(可能是某些版本不兼容)?任何帮助或见解非常感谢.

小智 8

当使用spring引导时,它只注册DefaultMethodEndpointAdapter配置注释驱动的Spring WS编程模型.这使得可以使用各种注释一样@Endpoint,@Payload自动侦测.

在我们的例子中,spring-ws端点必须将ws请求移交给camel端点,DefaultMethodEndpointAdapter不会为我们做那个工作.

下面是spring框架中执行端点适配器注册的代码部分,

private void initEndpointAdapters(ApplicationContext applicationContext)抛出BeansException {

    if (endpointAdapters == null) {
        Map<String, EndpointAdapter> matchingBeans = BeanFactoryUtils
                .beansOfTypeIncludingAncestors(applicationContext, EndpointAdapter.class, true, false);
Run Code Online (Sandbox Code Playgroud)

if(!matchingBeans.isEmpty()){endpointAdapters = new ArrayList(matchingBeans.values()); Collections.sort(endpointAdapters,new OrderComparator()); }

        else {
            endpointAdapters =
                    defaultStrategiesHelper.getDefaultStrategies(EndpointAdapter.class, applicationContext);
            if (logger.isDebugEnabled()) {
                logger.debug("No EndpointAdapters found, using defaults");
            }
        }
    }
} 
Run Code Online (Sandbox Code Playgroud)

当我们用弹簧启动,DefaultMethodEndpointAdapter被注册,因此第一"如果块"运行,因此它没有注册其他适配器一样MessageEndpointAdapter,PayloadEndpointAdapter等等.

在这种情况下我们需要的是,除了DefaultMethodEndpointAdapter必须注册MessageEndpointAdapter以将spring-ws卸载到camel端点之外.

所以在WebServiceConfig课堂上,添加以下代码,

@Bean
    public EndpointAdapter messageEndpointAdapter() {
        return new MessageEndpointAdapter();
    }
Run Code Online (Sandbox Code Playgroud)

然后交接魔法发生了.

Spring-ws和camel切换需要MessageEndpointAdapter.