Gradle:使用 Spring Boot 依赖项构建“fat jar”

Posted

技术标签:

【中文标题】Gradle:使用 Spring Boot 依赖项构建“fat jar”【英文标题】:Gradle: Build 'fat jar' with Spring Boot Dependencies 【发布时间】:2016-02-08 06:58:52 【问题描述】:

我正在使用 Gradle 构建一个非常简单的 Spring Boot 应用程序(99% 静态内容)并将其打包到一个带有嵌入式 tomcat 的 jar 中。

我尝试创建所说的 jar,起初结果是 86k 并且没有启动,因为它缺少一些 Spring 引导类。我得出的结论是,我制作的这个 jar 不包含应用程序的任何依赖项,因为我确实想要一个完全独立的 jar,所以我应该做更多的研究。

这时我发现了将from configurations.compile.collect it.isDirectory() ? it : zipTree(it) 部分添加到“jar”的建议,这会导致它引入所有依赖项。 (我希望)。我对三元运算符的概念很熟悉,我可以在这里看到它想要做什么。

不幸的是,它仍然无法正常工作!这是我在启动时遇到的错误,下面是我的 build.gradle。

我想要一个带有完全包含在 jar 中的嵌入式 tomcat 的 Spring Boot 应用程序。我在做一些非常规的事情吗? 在这一点上的任何帮助将不胜感激。

(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 我正在使用:

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

【问题讨论】:

【参考方案1】:

您不需要为自己制作额外的 gradle 配置来构建 spring-boot 应用程序的 fat-jar 工件,因为您使用 gradle spring boot 插件。它已经有一个任务bootRepackage 为您完成。您可以在官方用户指南here 和here 中阅读。

只需删除您为解压缩依赖项内容所做的所有工作,然后使用此任务获取应用程序的单个 jar 文件。

顺便说一句,您可能有兴趣查看其他一些解决方案,它可能会提供更好的存档大小,您可以阅读其中一个,称为 Capsule,in this article。

【讨论】:

我在文档中找到了 bootRepackage 任务,还没有尝试使用它,因为我觉得文档没有完全解释如何使用它。好吧,我错了,因为它和文档中显示的一样简单,而且效果和我希望的一样。也感谢 Capsule 的领导,我必须尝试一下。 @Stanislav 仅供参考,后一个链接不再存在。 ..从 Spring Boot 2.0 开始,gradle 任务被称为 bootjar(以及相应的 bootwar),参见spring.io/blog/2017/04/05/spring-boot-s-new-gradle-plugin【参考方案2】:

使用当前版本的 gradle,将其添加到 build.gradle 文件的顶部:

plugins 
    id "org.springframework.boot" version "2.0.0.RELEASE"

那么只需gradle build - 你不需要再做任何事情了。

请参阅this plugin's homepage 以查找最新版本。

【讨论】:

【参考方案3】:

我从@Stanislav 的回答中发现这个链接:https://docs.spring.io/spring-boot/docs/2.2.6.RELEASE/gradle-plugin/reference/html/#packaging-executable-wars-deployable 非常有帮助。

为了构建 jar,我使用了bootJar 任务来编译 jar。 (./gradlew bootJar)。我的项目没有bootRepackage 任务,并且使用./gradlew build 并没有生成包含所需所有依赖项的jar。也许这是我应该尝试使用dependsOn 之类的东西来配置的东西,但现在这对我有用。

我有一个多模块项目,所以单模块项目的配置可能不同。我还在我的依赖项中使用com.graphql-java:graphql-java-spring-boot-starter-webmvc:1.0 以及一些常规的 sping 启动依赖项,所以我的设置并不完全是普通的。

【讨论】:

以上是关于Gradle:使用 Spring Boot 依赖项构建“fat jar”的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot、Gradle 和非 Maven 依赖项 [重复]

Spring boot 和 Gradle 多模块项目,无法正确加载依赖项

如何在gradle中排除来自spring boot的依赖项

Spring Boot Gradle 多项目构建在测试期间看不到内部依赖项

删除 gradle 中的传递类路径依赖项

如何使用 spring boot 插件 2.0.x 从一个具有不同依赖项的 gradle 项目生成 2 个 jars