5

A simple Spring Boot application which just prints a "Hello World" when packaged as an deploy-able WAR is 11.5 MB. When I exploded the WAR, the web-inf/lib folder was the root cause having too many libraries.

  1. How to create the WAR with only the minimum necessary/dependent libraries ?
  2. While mentioning provided as scope for spring-boot-starter-tomcat , does the embedded Tomcat Server still get packaged along with the WAR ?

I was playing around with the 'gs-spring-boot-complete' project that comes with the Spring Test Suite (STS) and here is the default POM that came with it.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-spring-boot</artifactId>
    <version>0.1.0</version>
    <!-- ... -->
    <packaging>war</packaging>
    <!-- ... -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.10.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

        <!-- tag::actuator[] -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!-- end::actuator[] -->
        <!-- tag::tests[] -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- end::tests[] -->
    </dependencies>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <artifactId>maven-failsafe-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>integration-test</goal>
                            <goal>verify</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

Update: i removed the dependency on spring-boot-starter-tomcat and spring-boot-starter-actuator from the POM, still the WAR is 11.5 MB.

Currently there are only 2 direct dependencies spring-boot-starter-web & spring-boot-starter-test (i understand that this might in turn have other dependencies).

My question is that, even if I am not going to have an embedded Tomcat container, do "Spring Boot" applications generate such huge deploy-able WARs ? am trying to confirm if there is anything that could be done to have an optimized (i mean small sized) deploy-able WAR.

yathirigan
  • 5,619
  • 22
  • 66
  • 104

2 Answers2

6

If you have no interest in running your application as an executable war file and only want to deploy it to a servlet container then you can remove Spring Boot's Maven plugin and declare spring-boot-starter-tomcat as a provided dependency:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>example-app</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>       
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

Remove Spring Boot's Maven plugin will prevent provided dependencies from being packaging in your war file. Making spring-boot-starter-tomcat a provided dependency, rather than excluding it altogether, will allow you to run integration tests using embedded Tomcat.

This will give you a war file that's 7.6MB. Depending on your application and the technologies that you want to use, you may also want to consider excluding some of spring-boot-starter-web's transitive dependencies. For example, it's pulling in Hibernate Validator (> 0.5MB) and Jackson (> 1MB).

Andy Wilkinson
  • 108,729
  • 24
  • 257
  • 242
  • that's great... even-though i don't want to do this right away, i was curious to know the best practices being followed around. Even before not wanting to bloat my WAR file unnecessarily , I wanted to understand what was really going on and what else could be done. thank you – yathirigan Feb 17 '15 at 18:53
1

The intention is to create a war/jar with all your dependencies included. What is the minimum you want to deploy?

Id suggest removing the tomcat and actuator dependency for a start - then recheck the size

farrellmr
  • 1,815
  • 2
  • 15
  • 26
  • i removed the dependency on spring-boot-starter-tomcat and spring-boot-starter-actuator from the POM, still the WAR is 11.5 MB. Currently there are only 2 direct dependencies spring-boot-starter-web & spring-boot-starter-test (i understand that this might in turn have other dependencies). My question is that, even if I am not going to have an embeded Tomcat container, do "Spring Boot" applications generate such huge deploy-able WARs ? am trying to confirm if there is anything that could be done to have an optimized deploy-able WAR. – yathirigan Feb 17 '15 at 15:36
  • Just reading this link - http://spring.io/guides/gs/convert-jar-to-war/ - you have to declare the embedded preferences as provided to remove tomcat – farrellmr Feb 17 '15 at 15:41
  • yes, you can notice the pom content i've pasted. It is declared as "provided" in my POM – yathirigan Feb 17 '15 at 15:43
  • Oh I see - ive read you can use a shade plugin with maven. That might help reduce the size – farrellmr Feb 17 '15 at 15:47
  • 1
    just in-case for my reference, here is a good explanation on the maven shade plugin http://stackoverflow.com/questions/13620281/what-is-the-maven-shade-plugin-used-for-and-why-would-you-want-to-relocate-java – yathirigan Feb 17 '15 at 16:07
  • The shade plugin cannot possibly help I'm afraid. If you don't want the embedded tomcat, exclude it (don't make it provided), and remove the spring-boot-maven-plugin (that's the one that does the "shading"). – Dave Syer Feb 17 '15 at 16:26