Search code examples
javaspringcxf

Spring CXF Soap Web Service Under Tomcat: No Services Found


I'm trying to set-up a simple CXF Web Service running on Tomcat with CXF and Spring:

I have a Web Application initializer to bootstrap the CXF servlet:

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{
  @Override
  protected void registerContextLoaderListener(ServletContext servletContext)
  {
    CXFServlet cxfServlet = new CXFServlet();
    ServletRegistration.Dynamic dispatcher = servletContext.addServlet("cxf", cxfServlet);
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/services/*");
  }

  .....
}

I have a Spring configuration class:

@Configuration
public class WebServiceConfiguration
{
  @Bean
  public Endpoint endPoint()
  {
    EndpointImpl endpoint = new EndpointImpl(cxf(), eorthoWebService());
    endpoint.getHandlers().add(inboundRequestHandler());
    endpoint.getHandlers().add(outboundRequestHandler());
    //the below works and uses cxf's embedded Jetty server
    //endpoint.publish("http://localhost:9090/services/EorthoWebService");
    //this doesn't work
    endpoint.publish("/EorthoWebService");

    return endpoint;
  }

  @Bean
  public SpringBus cxf()
  {
    return new SpringBus();
  }

  @Bean
  public EorthoWebService eorthoWebService()
  {
    return new EorthoWebServiceImpl();
  }
}

I have a Web Service implementation:

@WebService(endpointInterface = "com.aoa.eortho.ws.service.EorthoWebService")
@SchemaValidation(type = SchemaValidationType.IN)
public class EorthoWebServiceImpl implements EorthoWebService {

    @WebMethod
    public RulesEngineOrthodonticSubmissionResponseEnv processRequest(RulesEngineOrthodonticSubmissionRequestEnv requestEnvelope) {
        ...
    }
}

When I hit /services I get the output:

No services have been found.

The only way I can it to work is by publishing as below which seems to publish it to an embedded Jetty server rather than the Tomcat instance it is deployed to:

endpoint.publish("http://localhost:9090/services/EorthoWebService");

What am I missing to get it working on Tomcat using:

endpoint.publish("/EorthoWebService");

Solution

  • The part you're missing is the spring contextscanning.

    From Baeldung -- A Guide to Apache CXF with Spring

    First, a Spring application context is created and configured to register a class containing configuration metadata:

    AnnotationConfigWebApplicationContext context 
        = new AnnotationConfigWebApplicationContext();
    context.register(ServiceConfiguration.class);
    

    The ServiceConfiguration class is annotated with the @Configuration annotation to provide bean definitions. This class is discussed in the next subsection. The following snippet shows how the Spring application context is added to the servlet context:

    container.addListener(new ContextLoaderListener(context));
    

    So, the complete class is:

    public class AppInitializer implements WebApplicationInitializer {
        @Override
        public void onStartup(ServletContext container) {
    
            AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
            context.register(ServiceConfiguration.class);
    
            container.addListener(new ContextLoaderListener(context));
    
            // Register and map the dispatcher servlet
            ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new CXFServlet());
            dispatcher.setLoadOnStartup(1);
    
            dispatcher.addMapping("/services/*");
        }
    }
    

    Which is different from your AbstractAnnotationConfigDispatcherServletInitializer extended class but when i override onStartup instead of registerContextLoaderListener it seems to work just as well. Hopefully this is enough to get you sorted out.

    Also, my Configuration class:

    @Configuration
    public class ServiceConfiguration {
    
        @Bean
        public Endpoint endpoint() {
            EndpointImpl endpoint = new EndpointImpl(cxf(), new HelloWorldImpl());
            endpoint.publish("/HelloWorld");
            return endpoint;
        }
    
        @Bean
        public SpringBus cxf() {
            return new SpringBus();
        }
    
    }