使用 Spring Boot“bootRun”启动的应用程序在包含 Gradle Vaadin 插件时会导致 NoClassDefFoundError
Posted
技术标签:
【中文标题】使用 Spring Boot“bootRun”启动的应用程序在包含 Gradle Vaadin 插件时会导致 NoClassDefFoundError【英文标题】:Application started with Spring Boot "bootRun" causes NoClassDefFoundError when including Gradle Vaadin plugin 【发布时间】:2019-01-22 07:00:27 【问题描述】:我的目标是建立一个简单的多模块项目,它使用 Spring Boot 2、Gradle 4.x 和 Vaadin 8.x 作为 UI。 Vaadin 目前只在其中一个子项目中使用,其他的提供服务或者只是库。
我从this really nice Spring tutorial 开始,它(尽管使用较旧的 Gradle 语法)生成了一个可以工作的测试项目。它包含一个“libaray”子项目和一个“应用程序”子项目,取决于前者。 “bootRun”和“bootJar”Gradle 任务都像一个魅力,在我将一些配置集中在父 build.grade 中之后仍然有效。
然后我将Vaadin Gradle Plugin 添加到“应用程序”项目并更改端点以显示一个简单的 vaadin 标签。
问题是,现在当使用“bootRun”时,启动的应用程序不再能够访问它所依赖的“库”中的类。如果我删除代码中的任何依赖项,该应用程序可以工作,但是一旦我从“库”(例如“MyService”)中引用一个类,它就会因“java.lang.ClassNotFoundException”而崩溃。
但是,当使用“bootJar”部署相同的应用程序并运行 jar 时,一切正常,因此可以解决模块间的依赖关系。
现在我想知道我是否缺乏理解,Vaadin Gradle 插件需要额外/不同的模块依赖配置?或者这可能是 Vaadin Gradle 插件中的错误或我的配置中的问题?
我已经阅读了这个插件的完整文档但没有得到任何线索,已经在网上搜索过,但在这个特定的上下文中我没有找到“NoClassDefFoundError”,也没有找到一个同时使用 Spring 的多模块项目示例引导和 Vaadin 8。
以下是相关示例代码(不包括导入):
hello.app.DemoApplication
@SpringBootApplication(scanBasePackages = "hello")
@RestController
public class DemoApplication
//Service defined in dependent sub-project
private final MyService myService;
public DemoApplication(MyService myService)
this.myService = myService;
public static void main(String[] args)
SpringApplication.run(DemoApplication.class, args);
hello.app.StartUI
/** Entry point for the Vaadin 8 UI */
@SpringUI
@SpringView
public class StartUI extends UI implements View
@Override
protected void init(final VaadinRequest request)
setContent(new Label("Hello vaadin"));
库gradle.properties
plugins id "io.spring.dependency-management" version "1.0.5.RELEASE"
ext springBootVersion = '2.0.3.RELEASE'
jar
baseName = 'library'
version = '0.0.1-SNAPSHOT'
dependencies
implementation('org.springframework.boot:spring-boot-starter')
testImplementation('org.springframework.boot:spring-boot-starter-test')
dependencyManagement
imports mavenBom("org.springframework.boot:spring-boot-dependencies:$springBootVersion")
应用程序gradle.properties
plugins
id "io.spring.dependency-management" version "1.0.5.RELEASE"
id "org.springframework.boot" version "2.0.3.RELEASE"
id 'com.devsoap.plugin.vaadin'version '1.3.1' //Add vaadin support
bootJar
baseName = 'application'
version = '0.0.1-SNAPSHOT'
dependencies
implementation project(':library') // Contains "MyService"
implementation('org.springframework.boot:spring-boot-starter-actuator')
implementation('org.springframework.boot:spring-boot-starter-web')
testImplementation('org.springframework.boot:spring-boot-starter-test')
父(根)项目build.gradle
subprojects
//Only plugins configured here applied to sub-projects.
apply plugin: "java-library"
apply plugin: "eclipse"
repositories mavenCentral()
sourceCompatibility = 1.8
当然,父 settings.gradle 引用子项目。
堆栈跟踪(有点缩短)
java.lang.IllegalStateException: Cannot load configuration class: hello.app.DemoApplication
at org.springframework.context.annotation.ConfigurationClassPostProcessor.enhanceConfigurationClasses(ConfigurationClassPostProcessor.java:414) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanFactory(ConfigurationClassPostProcessor.java:254) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:284) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:128) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:694) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
...
Caused by: java.lang.IllegalStateException: Unable to load cache item
at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:79) ~[spring-core-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34) ~[spring-core-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:116) ~[spring-core-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291) ~[spring-core-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:480) ~[spring-core-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:337) ~[spring-core-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.context.annotation.ConfigurationClassEnhancer.createClass(ConfigurationClassEnhancer.java:138) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.context.annotation.ConfigurationClassEnhancer.enhance(ConfigurationClassEnhancer.java:110) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.enhanceConfigurationClasses(ConfigurationClassPostProcessor.java:403) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
... 12 common frames omitted
Caused by: java.lang.NoClassDefFoundError: hello/service/MyService
at java.lang.Class.getDeclaredConstructors0(Native Method) ~[na:1.8.0_151]
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671) ~[na:1.8.0_151]
at java.lang.Class.getDeclaredConstructors(Class.java:2020) ~[na:1.8.0_151]
at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:566) ~[spring-core-5.0.7.RELEASE.jar:5.0.7.RELEASE]
...
Caused by: java.lang.ClassNotFoundException: hello.service.MyService
at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_151]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_151]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335) ~[na:1.8.0_151]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_151]
... 34 common frames omitted
更多信息:我在 Eclipse Photon 中使用带有 Gradle 4.3 的 Buildship 2.2 插件。
【问题讨论】:
【参考方案1】:我看到的一些事情:
您构建的不是 Java 库,而是 Java Web 应用程序,因此请忽略“java-library”插件。
管理插件的更好策略是使用 apply false 参数将它们全部注册到 parent 项目中。然后在子项目中正常应用插件。这样您就可以将所有插件依赖版本管理在一个地方
实现 配置相当新,许多插件不支持它(例如 gretty)。我会将它们切换为使用 compile 和 testCompile。
Spring 依赖管理插件确实具有侵入性,并非所有插件都支持它(Gradle Vaadin 插件就是其中之一)。我会跳过它,而是使用 Gradle 的 BOM 支持。 https://docs.gradle.org/4.6/userguide/managing_transitive_dependencies.html#sec:bom_import
【讨论】:
感谢您抽出宝贵时间提出建议。 你成就了我的一天。现在 bootRun 又开始工作了。 实际问题是我使用新的“api”与“实现”语法而不是“编译”(这就是我需要“java-library”插件的原因)。切换到编译和“java”插件解决了依赖问题。见this issue for the plugin。我还修改了 build.gradle 文件以使用没有依赖管理插件的“spring-boot-dependencies”BOM。花了一段时间,我在此过程中学到了很多东西 - 但似乎这与问题无关。以上是关于使用 Spring Boot“bootRun”启动的应用程序在包含 Gradle Vaadin 插件时会导致 NoClassDefFoundError的主要内容,如果未能解决你的问题,请参考以下文章
Gradle > 如何停止使用 gradle bootRun 启动的 Spring Boot 应用程序?
Spring boot 运行错误 bootRun 工作正常,但应用程序运行不工作
尝试使用 gradle bootrun 编译并获取找不到 spring-boot-gradle-plugin:1.4.0.BUILD-SNAPSHOT