是否必须仅在子模块中添加 spring-boot-starter-* 依赖项?

Posted

技术标签:

【中文标题】是否必须仅在子模块中添加 spring-boot-starter-* 依赖项?【英文标题】:Mandatory to add spring-boot-starter-* dependencies in child module only? 【发布时间】:2021-04-07 14:35:52 【问题描述】:

我有一个父模块 (A) 作为依赖项已包含/导入到子模块 (B) 中。

模块 A

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

模块 B

<dependencies>
            <dependency>
                <groupId>com.xyz</groupId>
                <artifactId>module-A</artifactId>
                <version>*module-A-version*<version>
            </dependency>
<dependencies>

问题:编译没有错误,并且成功创建了模块B(B.war)的战争工件。但是当我部署模块 B(即 B.war)时,它会因以下错误而失败。

线程“main”中的异常 java.lang.NoClassDefFoundError: org/springframework/beans/factory/config/YamlProcessor 在 java.lang.ClassLoader.defineClass1(本机方法) 在 java.lang.ClassLoader.defineClass(ClassLoader.java:763) 在 java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) 在 java.net.URLClassLoader.defineClass(URLClassLoader.java:467) 在 java.net.URLClassLoader.access$100(URLClassLoader.java:73) 在 java.net.URLClassLoader$1.run(URLClassLoader.java:368) 在 java.net.URLClassLoader$1.run(URLClassLoader.java:362) 在 java.security.AccessController.doPrivileged(本机方法) 在 java.net.URLClassLoader.findClass(URLClassLoader.java:361) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:424) 在 sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:357) 在 org.springframework.boot.env.YamlPropertySourceLoader.load(YamlPropertySourceLoader.java:57) 在 org.springframework.boot.env.PropertySourcesLoader.load(PropertySourcesLoader.java:127) 在 org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.loadIntoGroup(ConfigFileApplicationListener.java:462) 在 org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:449) 在 org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:374) 在 org.springframework.boot.context.config.ConfigFileApplicationListener.addPropertySources(ConfigFileApplicationListener.java:210) 在 org.springframework.boot.context.config.ConfigFileApplicationListener.postProcessEnvironment(ConfigFileApplicationListener.java:179) 在 org.springframework.boot.context.config.ConfigFileApplicationListener.onApplicationEnvironmentPreparedEvent(ConfigFileApplicationListener.java:166) 在 org.springframework.boot.context.config.ConfigFileApplicationListener.onApplicationEvent(ConfigFileApplicationListener.java:152) 在 org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:163) 在 org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:136) 在 org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:119) 在 org.springframework.boot.context.event.EventPublishingRunListener.publishEvent(EventPublishingRunListener.java:111) 在 org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:65) 在 org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:54) 在 org.springframework.boot.SpringApplication.doRun(SpringApplication.java:325) 在 org.springframework.boot.SpringApplication.run(SpringApplication.java:305) 在 org.springframework.boot.SpringApplication.run(SpringApplication.java:1124) 在 org.springframework.boot.SpringApplication.run(SpringApplication.java:1113) 在 com.propspace.intl.gateway.GatewayInternational.main(GatewayInternational.java:32) 引起:java.lang.ClassNotFoundException:org.springframework.beans.factory.config.YamlProcessor 在 java.net.URLClassLoader.findClass(URLClassLoader.java:381) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:424) 在 sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 32 更多

是不是我们总是必须在叶子模块中包含 spring-boot-starter-* 并且不能在一个共同的父模块中定义它?

【问题讨论】:

【参考方案1】:

在对 pom-starters 进行了几次 PoC 之后,确认只有 deployable 服务应该在其 pom.xml 中定义相应的 pom-starter。

因此 w.r.t 上面的层次结构子 B 必须具有如下定义,

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

A 可以包含任何其他非 pom-starters 的常见依赖项。

【讨论】:

以上是关于是否必须仅在子模块中添加 spring-boot-starter-* 依赖项?的主要内容,如果未能解决你的问题,请参考以下文章

仅在子例程中需要时才使用 Perl 模块

在子模块内添加 git 子模块(嵌套子模块)

iPhone UIView:是不是可以仅在子视图上启用用户交互?

是否可以添加检查所有子模块是否具有与父 pom 中定义的相同版本?

是否可以从 Maven 多模块项目的父模块中的配置文件夹加载 Spring-Boot 属性?

仅在子级别上应用 jq 过滤器,保持 JSON 的其余部分完好无损