spring-projects / spring-boot

Spring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.
https://spring.io/projects/spring-boot
Apache License 2.0
75.22k stars 40.7k forks source link

spring boot doesn't work in tomcat container #1194

Closed mjason3 closed 10 years ago

mjason3 commented 10 years ago

Hi,

I can run the spring boot in embeded tomcat. but after deploying to a tomcat container, i encounter this issue: Mon Jun 30 19:35:36 CST 2014 There was an unexpected error (type=Internal Server Error, status=500). org.apache.jsp.WEB_002dINF.views.documentation_jsp

wilkinsona commented 10 years ago

I think this may be a symptom of #1187. Which version of Boot are you using?

mjason3 commented 10 years ago

@wilkinsona I'm using the 1.1.3.RELEASE. Finally, i resolved it by adding jsp-api, servlet-api with scope "provided". Btw, Is an executable jar a recommended way or SpringBoot want to enable both jar and war? If the SpringBoot want to enable both two ways, i have to say, current support is terrible. My suggestion will be if the package type is war, automatically remove the embed tomcat/jetty dependencies.

wilkinsona commented 10 years ago

Thanks for following up. The problem you've seen should now be fixed in the 1.1.4 snapshots.

If you have no desire to deploy your application to a servlet container then, yes, an executable jar is the recommended way to package your application. What is the problem you're seeing with the current executable war support, beyond the problem you've reported here? What is it that makes you consider it to be "terrible"?

A war that's been repackaged by the Spring Boot Maven or Gradle plugin contains the embedded Tomcat/Jetty dependencies to allow it to be run as a self-contained executable or by deploying it to a Servlet container. If you know that you'll only ever deploy your application to a Servlet container you can easily build a traditional war file by not using the plugin or, in the case of Gradle, configuring it to disable repackaging.

mjason3 commented 10 years ago

Hi @wilkinsona , yes, the support of executable jar is cool. My goal is to use embed tomcat as a development env in IDE, and release it to a production env which is a tomcat or other web container. So i configure the package type as war. One issue is i have already reported above(glad to see it will be fixed soon) Another "issue" is i don't want my war package contains all the embed tomcat related dependencies like jasper which may result in conflicts.

mjason3 commented 10 years ago

@wilkinsona exclusion is a solution to exclude embed tomcat dependencies. However, SpringBoot is born to save such configuration effort. When I am switching between dev and prod, i hope there is a better way. That's why i say current war support is terrible. It's more like a feature request. :-)

wilkinsona commented 10 years ago

i don't want my war package contains all the embed tomcat related dependencies like jasper which may result in conflicts

There is only a chance of a conflict due to the bug in 1.1.3. If you use 1.1.2 or a 1.1.4 snapshot, the jars for the embedded servlet container and its dependencies will be packaged in WEB-INF/lib-provided/ and a Servlet container will ignore them. They'll only be used when you run in development, either directly in your IDE, or using java -jar.

You're paying a small price in terms of the size of your application's war file to gain seamless movement from running as a self-contained application at development time to deploying to a Servlet container when you go into production. This is the best that Boot can do as it's impossible for us to detect at build time whether you're building your app for development or production. If you really want different binaries for development and production, then you could use a profile in your build (assuming you're using Maven) to control whether or not Boot's plugin performs its repackaging.

mjason3 commented 10 years ago

That makes sense. Thanks for the detailed explanation, Andy! I think the following way is good enough for my use case

its dependencies will be packaged in WEB-INF/lib-provided/ and a Servlet container will ignore them

naruraghavan commented 10 years ago

I am using 1.1.4 and still unable to deploy the resulting war into a regular tomcat due to the embedded tomcat. I don't see lib-provided under WEB-INF. What could be wrong?

naruraghavan commented 10 years ago
configurations {
    querydslapt
    provided
}

buildscript {
    repositories {
        maven { url "http://repo.spring.io/libs-release" }
        maven { url "http://repo.spring.io/libs-snapshot" }
        mavenLocal()
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.1.4.RELEASE")
        classpath("org.flywaydb:flyway-gradle-plugin:3.0")
        classpath("com.h2database:h2:1.4.178")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'
apply plugin: 'flyway'
apply plugin: 'war'

jar {
    baseName = 'netstar-content-rest-services'
    version = '1.0.0'
}

war {
    baseName = 'ncrs'
}

sourceCompatibility = 1.7

//applicationDefaultJvmArgs = [
//        "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005"
//]

repositories {
    mavenLocal()
    mavenCentral()
    maven { url "http://repo.spring.io/libs-release" }
    maven { url "https://repository.jboss.org/nexus/content/repositories/releases" }
    maven { url "http://repo.spring.io/libs-snapshot" }
}

sourceSets {
    main.compileClasspath += configurations.provided
    test.compileClasspath += configurations.provided
    test.runtimeClasspath += configurations.provided
}

flyway {
    url = "jdbc:h2:tcp://localhost/./netstar-content"
    user = 'sa'
}

dependencies {
    versionManagement 'io.spring.platform:platform-versions:1.0.1.RELEASE@properties'

    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.springframework.boot:spring-boot-starter-data-jpa")
    compile("org.springframework.boot:spring-boot-starter-data-rest")
    compile("com.fasterxml.jackson.core:jackson-databind")
    compile("org.springframework.hateoas:spring-hateoas")

    compile("org.springframework.plugin:spring-plugin-core")
    compile("net.sf.ehcache:ehcache:2.8.3")
    compile("org.springframework:spring-context-support")
    compile("org.springframework.data:spring-data-redis")
    compile("org.springframework:spring-tx")
    compile("org.springframework:spring-tx-events:1.0.0.BUILD-SNAPSHOT")

    compile("redis.clients:jedis")
    compile("org.apache.commons:commons-pool2")
    compile("com.jayway.jsonpath:json-path")
    compile("com.h2database:h2")
    compile("org.jsoup:jsoup:1.7.3")
    compile('org.apache.commons:commons-lang3')
    compile("org.apache.httpcomponents:httpclient")
    compile("com.cenqua.clover:clover:3.3.0")
    compile("com.jolbox:bonecp:0.8.0.RELEASE")

    // for the anontation processor
    querydslapt group: 'com.mysema.querydsl', name: 'querydsl-jpa', version: '2.8.0', classifier: 'apt-one-jar', transitive: false

    compile group: 'org.projectlombok', name: 'lombok', version: '1.14.2'

    // for compiling
    compile("com.mysema.querydsl:querydsl-jpa")
    compile("com.mysema.querydsl:querydsl-apt")

    compile fileTree(dir: "${project.projectDir}/external/lib", includes: ['*.jar'])

    testCompile("org.springframework.boot:spring-boot-starter-test")

    //For tomcat
    provided("org.springframework.boot:spring-boot-starter-tomcat")

    compile("org.springframework.boot:spring-boot-starter-actuator")
}

//Querydsl

def generatedSrcDir = 'src/main/generated'
task createGeneratedSrcDir << {
    file(generatedSrcDir).mkdirs()
}
compileJava.dependsOn createGeneratedSrcDir

compileJava {
    options.compilerArgs << '-processor' << 'com.mysema.query.apt.jpa.JPAAnnotationProcessor' << '-s' << file(generatedSrcDir).absolutePath
}

clean {
    delete generatedSrcDir
}

task wrapper(type: Wrapper) {
    gradleVersion = '1.11'
}
wilkinsona commented 10 years ago

You need to declare the embedded server container dependencies in a configuration named providedRuntime as described here

mjason3 commented 10 years ago

@wilkinsona I have upgraded to 1.1.4 and there is a exception Exception in thread "main" java.lang.NoClassDefFoundError: javax/servlet/ServletContext Is this configuration incorrect?

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
wilkinsona commented 10 years ago

That configuration looks right to me. I've just double-checked by modifying the Web UI sample with the provided dependencies and a SpringBootServletInitializer subclass. It ran successfully on Tomcat 7.0.54.

If you want me to investigate further, knowing the version of Tomcat that you're using and the full stack trace of the exception would help. Even better would be small app that reproduces the problem.

mjason3 commented 10 years ago

I encountered this exception only in IntelliJ community edition. However, in eclipse, everything goes well.

mjason3 commented 10 years ago

For the project to reproduce, you can use the jsp project in spring-boot samples.

wilkinsona commented 10 years ago

That sounds like a bug in IntelliJ. Perhaps JetBrains can help.

xilin commented 9 years ago

@mjason3 It seems IntelliJ always has this problem. Change the Module Setting of your project, go to the dependencies tab, and set scope into compile from provided for all embed:tomcat* dependencies.

mdjnewman commented 9 years ago

I can confirm that the IntelliJ error happens for me when I try to run a @SpringBootApplication class directly (without using maven/gradle). It happens in both versions on IntelliJ.

It is fixed temporarily if you follow the instructions @xilin, but these changes are overridden anytime the Gradle project is reimported (and it's annoying to have to tell new devs to do this).

JerseyGood commented 9 years ago

@xilin It works like a charm~

ccampo133 commented 9 years ago

Can confirm that @xilin's solution works. Seems like this is an IntelliJ problem. Does anybody know if theres a ticket opened with JetBrains?

snicoll commented 9 years ago

https://youtrack.jetbrains.com/issue/IDEA-137364

asegarra commented 9 years ago

Just wanted to say this happens in NetBeans also as it runs the main class using Maven exec plugin if you right click and select Run File.. My fix was to create a maven profile that adds these with default scope and select the profile as the netbeans run configuration.

bigslip commented 9 years ago

it may not be a intelij bug, just tried to change like this :+1:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>compile</scope>
        </dependency>

and, everything works

snicoll commented 9 years ago

well, of course.

You are working around the bug: the link above states that IJ does not manage provided dependencies properly. If you switch them to compile you're no longer affected by the bug....

frankcastro commented 8 years ago

Xi Lin Thank you very much for solving the problem I was having.

Regards

ceoaliongroo commented 7 years ago

In my case just change the scope to compile and generate 2 artifact one war explode with all the elements. And other war archive with the war exploded inside.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>compile</scope>
</dependency>