How do I tell Spring Boot to ignore Jetty and always use Tomcat?

MarSik picture MarSik · Jul 21, 2014 · Viewed 11.7k times · Source

I have the following setup:

spring-boot application (using embedded tomcat)
spring-date-neo4j (embedded mode)
spring-websockets

and neo4j-browser included using (the goal is to be able to use REST and web browser to debug embedded database):

    <dependency>
        <groupId>org.neo4j.app</groupId>
        <artifactId>neo4j-server</artifactId>
        <version>${neo4j.version}</version>
        <exclusions>
            <exclusion>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
            </exclusion>
            <exclusion>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-access</artifactId>
            </exclusion>
            <exclusion>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
            </exclusion>
            <exclusion>
                <artifactId>javax.servlet</artifactId>
                <groupId>org.eclipse.jetty.orbit</groupId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.neo4j.app</groupId>
        <artifactId>neo4j-server</artifactId>
        <version>${neo4j.version}</version>
        <classifier>static-web</classifier>
        <exclusions>
            <exclusion>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
            </exclusion>
            <exclusion>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-access</artifactId>
            </exclusion>
            <exclusion>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
            </exclusion>
            <exclusion>
                <artifactId>javax.servlet</artifactId>
                <groupId>org.eclipse.jetty.orbit</groupId>
            </exclusion>
        </exclusions>
    </dependency>

And started using:

@Autowired
@Bean(destroyMethod = "shutdown")
public GraphDatabaseService graphDatabaseService(DatabaseConfiguration dbConf) {
    // removed with every maven clear
    return new GraphDatabaseFactory().newEmbeddedDatabase(dbConf.getDbPath());

    // stays after clear
    //return new EmbeddedGraphDatabase("./data/neo4j.db");
}

@Bean(destroyMethod = "stop")
public WrappingNeoServerBootstrapper serverWrapper(GraphDatabaseService db) {
    WrappingNeoServerBootstrapper wrapper = new WrappingNeoServerBootstrapper((GraphDatabaseAPI)db);
    wrapper.start();
    return wrapper;
}

And spring boot is insisting on trying Jetty as the servlet container even with the following config annotations for the main app class:

@EnableAutoConfiguration(exclude = EmbeddedServletContainerAutoConfiguration.EmbeddedJetty.class)
@ComponentScan
@EnableWebMvc
@Configuration
public class WebApplication extends WebMvcConfigurerAdapter {

But the jetty version Spring uses (8) does not support web sockets so I am getting

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean
with name 'jettyEmbeddedServletContainerFactory' defined in class path resource 
[org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfiguration$EmbeddedJetty.class]:
Initialization of bean failed; nested exception is java.lang.IllegalStateException:
Websockets are currently only supported in Tomcat (found class org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory).

How do I tell Spring Boot to ignore Jetty and always use Tomcat?

The dependency tree:

[INFO] Building webapp 1.0
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ webapp ---
[INFO] webapp:war:1.0
[INFO] +- common:jar:1.0:compile
[INFO] |  +- javax.validation:validation-api:jar:1.1.0.Final:compile
[INFO] |  +- org.springframework.data:spring-data-neo4j:jar:3.1.0.RELEASE:compile
[INFO] |  |  +- org.aspectj:aspectjrt:jar:1.7.4:compile
[INFO] |  |  +- org.springframework.data:spring-data-commons:jar:1.8.0.RELEASE:compile
[INFO] |  |  +- org.neo4j:neo4j-cypher-dsl:jar:2.0.1:compile
[INFO] |  |  +- org.neo4j:neo4j:jar:2.0.3:compile
[INFO] |  |  +- org.slf4j:slf4j-api:jar:1.7.7:compile
[INFO] |  |  \- org.slf4j:jcl-over-slf4j:jar:1.7.7:compile
[INFO] |  +- commons-codec:commons-codec:jar:1.9:compile
[INFO] |  +- org.apache.poi:poi:jar:3.10-FINAL:compile
[INFO] |  +- org.apache.poi:poi-scratchpad:jar:3.10-FINAL:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.3.3:compile
[INFO] |  \- com.fasterxml.jackson.core:jackson-databind:jar:2.3.3:compile
[INFO] |     \- com.fasterxml.jackson.core:jackson-core:jar:2.3.3:compile
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:1.0.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:1.0.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot:jar:1.0.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-autoconfigure:jar:1.0.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:1.0.2.RELEASE:compile
[INFO] |  |  |  +- org.slf4j:jul-to-slf4j:jar:1.7.7:compile
[INFO] |  |  |  +- org.slf4j:log4j-over-slf4j:jar:1.7.7:compile
[INFO] |  |  |  \- ch.qos.logback:logback-classic:jar:1.1.2:compile
[INFO] |  |  |     \- ch.qos.logback:logback-core:jar:1.1.2:compile
[INFO] |  |  \- org.yaml:snakeyaml:jar:1.13:runtime
[INFO] |  \- org.springframework.boot:spring-boot-starter-tomcat:jar:1.0.2.RELEASE:compile
[INFO] |     +- org.apache.tomcat.embed:tomcat-embed-el:jar:7.0.52:compile
[INFO] |     \- org.apache.tomcat.embed:tomcat-embed-logging-juli:jar:7.0.52:compile
[INFO] +- org.springframework:spring-core:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-context:jar:4.0.3.RELEASE:compile
[INFO] |  \- org.springframework:spring-expression:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-beans:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework.security:spring-security-web:jar:3.2.4.RELEASE:compile
[INFO] |  +- aopalliance:aopalliance:jar:1.0:compile
[INFO] |  \- org.springframework.security:spring-security-core:jar:3.2.3.RELEASE:compile
[INFO] +- org.springframework.security:spring-security-config:jar:3.2.4.RELEASE:compile
[INFO] +- org.springframework.security:spring-security-taglibs:jar:3.2.4.RELEASE:compile
[INFO] |  \- org.springframework.security:spring-security-acl:jar:3.2.3.RELEASE:compile
[INFO] |     \- org.springframework:spring-jdbc:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-webmvc:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-web:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-websocket:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-messaging:jar:4.0.3.RELEASE:compile
[INFO] +- org.apache.tomcat.embed:tomcat-embed-websocket:jar:7.0.52:compile
[INFO] |  \- org.apache.tomcat.embed:tomcat-embed-core:jar:7.0.52:compile
[INFO] +- org.freemarker:freemarker:jar:2.3.20:compile
[INFO] +- org.springframework:spring-context-support:jar:4.0.3.RELEASE:compile
[INFO] +- net.glxn:qrgen:jar:1.4:compile
[INFO] |  \- com.google.zxing:javase:jar:3.0.0:compile
[INFO] |     \- com.google.zxing:core:jar:3.0.0:compile
[INFO] +- org.springframework:spring-tx:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-aop:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-aspects:jar:4.0.3.RELEASE:compile
[INFO] |  \- org.aspectj:aspectjweaver:jar:1.7.4:compile
[INFO] +- org.hibernate:hibernate-validator:jar:5.1.1.Final:compile
[INFO] |  +- org.jboss.logging:jboss-logging:jar:3.1.3.GA:compile
[INFO] |  \- com.fasterxml:classmate:jar:1.0.0:compile
[INFO] +- javax.el:javax.el-api:jar:2.2.4:compile
[INFO] +- org.glassfish.web:javax.el:jar:2.2.4:compile
[INFO] +- org.apache.commons:commons-lang3:jar:3.3.2:compile
[INFO] +- commons-io:commons-io:jar:2.4:compile
[INFO] +- commons-fileupload:commons-fileupload:jar:1.3.1:compile
[INFO] +- org.jsoup:jsoup:jar:1.7.3:compile
[INFO] +- com.sun.jersey:jersey-server:jar:1.18:compile
[INFO] |  +- asm:asm:jar:3.1:compile
[INFO] |  \- com.sun.jersey:jersey-core:jar:1.18:compile
[INFO] +- com.sun.jersey:jersey-servlet:jar:1.18:compile
[INFO] +- org.neo4j.app:neo4j-server:jar:2.0.3:compile
[INFO] |  +- org.neo4j:neo4j:pom:2.0.3:compile
[INFO] |  |  +- org.neo4j:neo4j-lucene-index:jar:2.0.3:compile
[INFO] |  |  |  \- org.apache.lucene:lucene-core:jar:3.6.2:compile
[INFO] |  |  +- org.neo4j:neo4j-graph-algo:jar:2.0.3:compile
[INFO] |  |  +- org.neo4j:neo4j-udc:jar:2.0.3:compile
[INFO] |  |  +- org.neo4j:neo4j-graph-matching:jar:2.0.3:compile
[INFO] |  |  \- org.neo4j:neo4j-jmx:jar:2.0.3:compile
[INFO] |  +- org.neo4j:neo4j-kernel:jar:2.0.3:compile
[INFO] |  |  \- org.apache.geronimo.specs:geronimo-jta_1.1_spec:jar:1.1.1:compile
[INFO] |  +- org.neo4j:server-api:jar:2.0.3:compile
[INFO] |  |  \- org.neo4j.3rdparty.javax.ws.rs:jsr311-api:jar:1.1.2.r612:compile
[INFO] |  +- org.neo4j:neo4j-cypher:jar:2.0.3:compile
[INFO] |  |  +- org.neo4j:neo4j-cypher-commons:jar:2.0.3:compile
[INFO] |  |  +- org.neo4j:neo4j-cypher-compiler-1.9:jar:2.0.3:compile
[INFO] |  |  +- org.neo4j:neo4j-cypher-compiler-2.0:jar:2.0.3:compile
[INFO] |  |  |  +- org.parboiled:parboiled-scala_2.10:jar:1.1.6:compile
[INFO] |  |  |  |  \- org.parboiled:parboiled-core:jar:1.1.6:compile
[INFO] |  |  |  \- net.sf.opencsv:opencsv:jar:2.0:compile
[INFO] |  |  +- com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:jar:1.3.1:compile
[INFO] |  |  \- org.scala-lang:scala-library:jar:2.10.3:compile
[INFO] |  +- org.neo4j.app:neo4j-browser:jar:2.0.3:compile
[INFO] |  +- org.codehaus.janino:janino:jar:2.6.1:compile
[INFO] |  |  \- org.codehaus.janino:commons-compiler:jar:2.6.1:compile
[INFO] |  +- org.eclipse.jetty:jetty-server:jar:9.0.5.v20130815:compile
[INFO] |  |  +- org.eclipse.jetty:jetty-http:jar:9.0.5.v20130815:compile
[INFO] |  |  \- org.eclipse.jetty:jetty-io:jar:9.0.5.v20130815:compile
[INFO] |  +- org.eclipse.jetty:jetty-webapp:jar:8.1.14.v20131031:compile
[INFO] |  |  +- org.eclipse.jetty:jetty-xml:jar:8.1.14.v20131031:compile
[INFO] |  |  \- org.eclipse.jetty:jetty-servlet:jar:8.1.14.v20131031:compile
[INFO] |  |     \- org.eclipse.jetty:jetty-security:jar:8.1.14.v20131031:compile
[INFO] |  +- commons-configuration:commons-configuration:jar:1.6:compile
[INFO] |  |  +- commons-collections:commons-collections:jar:3.2.1:compile
[INFO] |  |  +- commons-lang:commons-lang:jar:2.4:compile
[INFO] |  |  +- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] |  |  \- commons-beanutils:commons-beanutils-core:jar:1.8.0:compile
[INFO] |  +- commons-digester:commons-digester:jar:1.8.1:compile
[INFO] |  |  \- commons-beanutils:commons-beanutils:jar:1.8.0:compile
[INFO] |  +- org.codehaus.jackson:jackson-jaxrs:jar:1.9.7:compile
[INFO] |  |  +- org.codehaus.jackson:jackson-core-asl:jar:1.9.7:compile
[INFO] |  |  \- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.7:compile
[INFO] |  +- org.rrd4j:rrd4j:jar:2.0.7:compile
[INFO] |  +- org.mozilla:rhino:jar:1.7R4:compile
[INFO] |  +- bouncycastle:bcprov-jdk16:jar:140:compile
[INFO] |  +- com.sun.jersey.contribs:jersey-multipart:jar:1.9:compile
[INFO] |  |  \- org.jvnet:mimepull:jar:1.6:compile
[INFO] |  \- org.neo4j:neo4j-shell:jar:2.0.3:compile
[INFO] |     \- org.apache.servicemix.bundles:org.apache.servicemix.bundles.jline:jar:0.9.94_1:compile
[INFO] +- org.neo4j.app:neo4j-server:jar:static-web:2.0.3:compile
[INFO] +- org.eclipse.jetty:jetty-util:jar:9.0.7.v20131107:compile
[INFO] +- com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:jar:r239:compile
[INFO] |  +- com.google.guava:guava:jar:17.0:compile (version selected from constraint [11.0,))
[INFO] |  \- com.google.code.findbugs:jsr305:jar:3.0.0:compile (version selected from constraint [1.3.9,))
[INFO] +- junit:junit:jar:4.11:test
[INFO] |  \- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] +- org.mockito:mockito-all:jar:1.9.5:test
[INFO] +- org.springframework:spring-test:jar:4.0.3.RELEASE:test
[INFO] +- org.mockito:mockito-core:jar:1.9.5:test
[INFO] |  \- org.objenesis:objenesis:jar:1.0:test
[INFO] \- org.hamcrest:hamcrest-library:jar:1.3:test

Answer

Andy Wilkinson picture Andy Wilkinson · Jul 21, 2014

Boot's using Jetty as it's on the classpath. The attempt to exclude it by excluding EmbeddedServletContainerAutoConfiguration.EmbeddedJetty.class doesn't work as EmdeddedJetty isn't an auto-configuration class. EmbeddedServletContainerAutoConfiguration is an auto-configuration class and you could exclude it, but then you'd also lose embedded Tomcat support which I don't think is what you want. The easiest thing to do is to eliminate Jetty from your application's classpath.

The dependency tree output shows that you've still got transitive dependencies on org.eclipse.jetty:jetty-server and org.eclipse.jetty:jetty-webapp, both of which are being pulled in by your direct dependency on org.neo4j.app:neo4j-server. Update your pom to exclude them:

<dependency>
    <groupId>org.neo4j.app</groupId>
    <artifactId>neo4j-server</artifactId>
    <version>${neo4j.version}</version>
    <classifier>static-web</classifier>
    <exclusions>
        <exclusion>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </exclusion>
        <exclusion>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-access</artifactId>
        </exclusion>
        <exclusion>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
        </exclusion>
        <exclusion>
            <artifactId>javax.servlet</artifactId>
            <groupId>org.eclipse.jetty.orbit</groupId>
        </exclusion>
        <exclusion>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-webapp</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Update: if excluding Jetty from the dependencies isn't an option, then you can declare your own TomcatEmbeddedServletContainerFactory bean:

@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
    return new TomcatEmbeddedServletContainerFactory();
}

This will prevent the auto-configuration of the embedded Jetty server as it's conditional on there being no EmbeddedServletContainerFactory bean in the application context.