Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

spring-boot with tomcat and cxf-servlet

I'm trying to stand up an embedded Tomcat with spring-boot. I want to use CXF for a set of web services in the app but I can not figure out how to stand up the CXF servlet.

My Main class looks like this...

@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackages={"com.connecture.services.documentservice.webservice"})
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(new Class[] { Application.class, CfxInitializer.class }, args);
    }
    
    @Bean
  public EmbeddedServletContainerFactory embeddedServletContainerFactory() {
      TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory("", 8080);
      return factory;
  }

}

And my CfxInitializer like this...

public class CfxInitializer implements ServletContextInitializer
{

  @Override
  public void onStartup(ServletContext servletContext) throws ServletException
  {
    XmlWebApplicationContext rootContext = new XmlWebApplicationContext();  
    rootContext.setConfigLocations(new String[] { "classpath*:applicationContext.xml" });  
    servletContext.addListener(new ContextLoaderListener(rootContext));  

    ServletRegistration.Dynamic dispatcher = servletContext.addServlet("CXFServlet", CXFServlet.class);  
    dispatcher.addMapping("/api/*");  
  }

}

When I try to build and start the jar with the typical command ./gradlew build && java -jar build/libs/gs-spring-boot-0.1.0.jar

I get an Exception for multiple Contexts.

Java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:277)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4971)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5467)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)

Here is a more complete pastebin - http://pastebin.com/bcJ2ULhM

----------------------------------------------------------------------------------

Similarly to Dave's answer I was able to fix it by removing the ServletContextInitializer and adding a bean to the Application Class.

@Bean
  public ServletRegistrationBean servletRegistrationBean(){
      return new ServletRegistrationBean(new CXFServlet(),"/api/*");
  }
like image 786
jeremyjjbrown Avatar asked Dec 25 '22 08:12

jeremyjjbrown


1 Answers

The Spring Boot embedded servlet features are designed to work with Servlet and ServletRegistration @Beans, and not with the ContextLoaderListener (which looks like it is trying to steal the ServletContext attribute for the root context). Try adding a ServletRegistration for your servlet instead; if it is Spring aware, assuming it has an interface that lets you change the application context or the context location, then you should be able to configure it in the registration.

like image 163
Dave Syer Avatar answered Jan 06 '23 04:01

Dave Syer