Gradle: Build ‘fat jar’ with Spring Boot Dependencies

Tags: , , ,



I am using Gradle to build and package a very simple spring boot application (99% static content) into a jar with embedded tomcat.

I tried creating said jar, at first the result was 86k and did not launch, because it was missing some Spring boot classes. I concluded this jar I made contained none of the application’s dependencies, and since I did want a completely self-contained jar, I should do more research.

This is when I discovered the advice to add the from {configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } section to the ‘jar’ which causes it to pull in all of the dependencies. (I hope). I’m familiar with the idea of the ternary operator and I can see what it’s trying to do here.

Unfortunately it is still not working! Here is the error I get on launch, and below is my build.gradle.

I want a spring boot application with embedded tomcat fully contained in a jar. Am I doing something highly unconventional?
Any help at this point would be greatly appreciated.

(About 80 lines of successful Spring Boot launch messages followed immediately by:
18:16:54.890 [main] WARN  o.s.b.c.e.AnnotationConfigEmbeddedWebApplicationContext - Exception encountered during context initialization - cancelling refresh attempt
org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:132) [SpringWsTest1.jar:na]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:474) ~[SpringWsTest1.jar:na]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:117) [SpringWsTest1.jar:na]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:689) [SpringWsTest1.jar:na]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:321) [SpringWsTest1.jar:na]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:969) [SpringWsTest1.jar:na]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:958) [SpringWsTest1.jar:na]
    at ws.Application.main(Application.java:11) [SpringWsTest1.jar:na]
Caused by: org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.getEmbeddedServletContainerFactory(EmbeddedWebApplicationContext.java:182) [SpringWsTest1.jar:na]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:155) [SpringWsTest1.jar:na]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:129) [SpringWsTest1.jar:na]
    ... 7 common frames omitted
18:16:54.891 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@3b084709: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,application,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor,demoController,greetingController,org.springframework.boot.autoconfigure.AutoConfigurationPackages]; root of factory hierarchy
18:16:54.891 [main] ERROR o.s.boot.SpringApplication - Application startup failed
org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:132) ~[SpringWsTest1.jar:na]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:474) ~[SpringWsTest1.jar:na]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:117) ~[SpringWsTest1.jar:na]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:689) [SpringWsTest1.jar:na]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:321) [SpringWsTest1.jar:na]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:969) [SpringWsTest1.jar:na]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:958) [SpringWsTest1.jar:na]
    at ws.Application.main(Application.java:11) [SpringWsTest1.jar:na]
Caused by: org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.getEmbeddedServletContainerFactory(EmbeddedWebApplicationContext.java:182) ~[SpringWsTest1.jar:na]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:155) ~[SpringWsTest1.jar:na]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:129) ~[SpringWsTest1.jar:na]
    ... 7 common frames omitted
Exception in thread "main" org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:132)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:474)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:117)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:689)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:321)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:969)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:958)
    at ws.Application.main(Application.java:11)
Caused by: org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.getEmbeddedServletContainerFactory(EmbeddedWebApplicationContext.java:182)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:155)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:129)
    ... 7 more

build.gradle I am using:

println System.getProperty("java.home")

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.2.7.RELEASE")
    }
}

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


jar {
    manifest {
        attributes 'Main-Class': 'ws.Application'
    }

    from {
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
    }
}


repositories {
    mavenCentral()
}


dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    testCompile("junit:junit")
}

task wrapper(type: Wrapper) {
    gradleVersion = '2.3'
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

Answer

You don’t need to make yourself additional gradle configurations for building a fat-jar artifact of spring-boot application, since you use a gradle spring boot plugin. It already has a task bootRepackage to do it for you. You can read about it in official user guide here and here.

Just delete all you’ve done to unzip dependencies content and use this task to get a single jar file with your application.

By the way, you may be interested to look at some other solution, which possibly could provide a better archive sizes, you can read about one of them, called Capsule, in this article.



Source: stackoverflow