spring-boot-starter-parent in independent module导致其bean在依赖模块中不可见
spring-boot-starter-parent in independent module causes its beans not be seen in dependent modules
我有一个聚合器 POM,它引用了 2 个模块 'appA' 和 'appB'。
'appB' 依赖于 'appA' 作为依赖项
'appB' 有 'spring-boot-starter-parent' 作为父 POM
'appA' 在包 "com.multipom.config"
中定义了一个 bean ('hwBean')
当 'appB' 应用程序运行时,仅当 'appA' 不使用时它才会看到 'hwBean'
'spring-boot-starter-parent' 作为父 POM。
当 'appA' 使用 'spring-boot-starter-parent' 作为父 POM 时,'appA' 中定义的 'hwBean' bean 在 'appB' 中不可用。这是 spring 引导错误吗?
in AppA module
----com.multipom.App_A.java-----
package com.multipom;
@SpringBootApplication
public class App_A {
public static void main(String[] args) {
SpringApplication.run(App_A.class, args);
}
}
----com.multipom.config.ApplicationConfig.java
package com.multipom.config;
@Configuration
public class ApplicationConfig {
@Bean
public String hwBean () {
return "Hello World";
}
}
in AppB module
----com.multipom.App_B.java-----
package com.multipom;
@SpringBootApplication
public class App_B {
public static void main(String[] args) {
SpringApplication.run(App_B.class, args);
}
}
root/pom.xml
<groupId>com.splitpom</groupId>
<artifactId>root</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>./appA</module>
<module>./appB</module>
</modules>
appB/pom.xml
<groupId>com.multipom</groupId>
<artifactId>appB</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>appB</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>com.multipom</groupId>
<artifactId>appA</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
appA/pom.xml (CASE 1)
<groupId>com.multipom</groupId>
<artifactId>appA</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>appA</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
appA/pom.xml (CASE 2)
<groupId>com.multipom</groupId>
<artifactId>appA</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>appA</name>
<parent>
<groupId>com.splitpom</groupId>
<artifactId>root</artifactId>
<version>1.0.0</version>
</parent>
$ java -jar appA-0.0.1-SNAPSHOT.jar
2017-03-18 11:23:23.340 TRACE 26149 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Scanning URL [jar:file:/multipom/appA/target/appA-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/config/ApplicationConfig.class]
2017-03-18 11:23:23.415 DEBUG 26149 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Identified candidate component class: URL [jar:file:/multipom/appA/target/appA-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/config/ApplicationConfig.class]
2017-03-18 11:23:23.416 TRACE 26149 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Scanning URL [jar:file:/multipom/appA/target/appA-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/App_A.class]
2017-03-18 11:23:23.430 TRACE 26149 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Ignored because not matching any filter: URL [jar:file:/multipom/appA/target/appA-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/App_A.class]
2017-03-18 11:23:24.084 DEBUG 26149 --- [ main] a.ConfigurationClassBeanDefinitionReader : Registering bean definition for @Bean method com.multipom.config.ApplicationConfig.hwBean()
案例 1:如果 'appA' 使用 'spring-boot-starter-parent' 作为父 POM(注意这里 'appB' 没有从 'appA' [=27] 中找到 'hwBean' =]
$ java -jar appB-0.0.1-SNAPSHOT.jar
2017-03-18 11:24:31.461 TRACE 26203 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Scanning URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/App_B.class]
2017-03-18 11:24:31.546 TRACE 26203 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Ignored because not matching any filter: URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/App_B.class]
案例 2:如果 'appA' 不使用 'spring-boot-starter-parent' 作为父 POM(注意这里 'appB' 确实从 'appA' 中找到 'hwBean'。
$ java -jar appB-0.0.1-SNAPSHOT.jar
2017-03-18 12:03:28.261 TRACE 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Scanning URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/App_B.class]
2017-03-18 12:03:28.316 TRACE 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Ignored because not matching any filter: URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/App_B.class]
2017-03-18 12:03:28.316 TRACE 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Scanning URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/appA-0.0.1-SNAPSHOT.jar!/com/multipom/App_A.class]
2017-03-18 12:03:28.324 DEBUG 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Identified candidate component class: URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/appA-0.0.1-SNAPSHOT.jar!/com/multipom/App_A.class]
2017-03-18 12:03:28.325 TRACE 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Scanning URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/appA-0.0.1-SNAPSHOT.jar!/com/multipom/config/ApplicationConfig.class]
2017-03-18 12:03:28.330 DEBUG 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Identified candidate component class: URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/appA-0.0.1-SNAPSHOT.jar!/com/multipom/config/ApplicationConfig.class]
2017-03-18 12:03:28.348 DEBUG 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning
2017-03-18 12:03:28.373 TRACE 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Scanning URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/App_B.class]
2017-03-18 12:03:28.384 DEBUG 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Identified candidate component class: URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/App_B.class]
2017-03-18 12:03:28.385 TRACE 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Scanning URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/appA-0.0.1-SNAPSHOT.jar!/com/multipom/App_A.class]
2017-03-18 12:03:28.388 TRACE 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Ignored because not matching any filter: URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/appA-0.0.1-SNAPSHOT.jar!/com/multipom/App_A.class]
2017-03-18 12:03:28.389 TRACE 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Scanning URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/appA-0.0.1-SNAPSHOT.jar!/com/multipom/config/ApplicationConfig.class]
2017-03-18 12:03:28.390 DEBUG 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Identified candidate component class: URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/appA-0.0.1-SNAPSHOT.jar!/com/multipom/config/ApplicationConfig.class]
2017-03-18 12:03:29.123 DEBUG 27097 --- [ main] a.ConfigurationClassBeanDefinitionReader : Registering bean definition for @Bean method com.multipom.config.ApplicationConfig.hwBean()
问题是spring-boot-maven-plugin 打包依赖jar 的方式。在默认设置中,此插件将 jar 打包为一种特殊的可执行 jar 格式,将所有 类 置于 /BOOT-INF/classes/... 下。如果您的 jar 被用作另一个模块中的依赖项,则您不需要想要那个。相反,您的 jar 必须是一个普通的扁平 jar,这样所有包含的 beans 都可以被依赖的应用程序发现。解决方案是将以下内容添加到 spring-boot-maven-plugin
部分(在 appA/pom.xml 中):
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
我有一个聚合器 POM,它引用了 2 个模块 'appA' 和 'appB'。 'appB' 依赖于 'appA' 作为依赖项 'appB' 有 'spring-boot-starter-parent' 作为父 POM 'appA' 在包 "com.multipom.config"
中定义了一个 bean ('hwBean')当 'appB' 应用程序运行时,仅当 'appA' 不使用时它才会看到 'hwBean' 'spring-boot-starter-parent' 作为父 POM。 当 'appA' 使用 'spring-boot-starter-parent' 作为父 POM 时,'appA' 中定义的 'hwBean' bean 在 'appB' 中不可用。这是 spring 引导错误吗?
in AppA module
----com.multipom.App_A.java-----
package com.multipom;
@SpringBootApplication
public class App_A {
public static void main(String[] args) {
SpringApplication.run(App_A.class, args);
}
}
----com.multipom.config.ApplicationConfig.java
package com.multipom.config;
@Configuration
public class ApplicationConfig {
@Bean
public String hwBean () {
return "Hello World";
}
}
in AppB module
----com.multipom.App_B.java-----
package com.multipom;
@SpringBootApplication
public class App_B {
public static void main(String[] args) {
SpringApplication.run(App_B.class, args);
}
}
root/pom.xml
<groupId>com.splitpom</groupId>
<artifactId>root</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>./appA</module>
<module>./appB</module>
</modules>
appB/pom.xml
<groupId>com.multipom</groupId>
<artifactId>appB</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>appB</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>com.multipom</groupId>
<artifactId>appA</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
appA/pom.xml (CASE 1)
<groupId>com.multipom</groupId>
<artifactId>appA</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>appA</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
appA/pom.xml (CASE 2)
<groupId>com.multipom</groupId>
<artifactId>appA</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>appA</name>
<parent>
<groupId>com.splitpom</groupId>
<artifactId>root</artifactId>
<version>1.0.0</version>
</parent>
$ java -jar appA-0.0.1-SNAPSHOT.jar
2017-03-18 11:23:23.340 TRACE 26149 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Scanning URL [jar:file:/multipom/appA/target/appA-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/config/ApplicationConfig.class]
2017-03-18 11:23:23.415 DEBUG 26149 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Identified candidate component class: URL [jar:file:/multipom/appA/target/appA-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/config/ApplicationConfig.class]
2017-03-18 11:23:23.416 TRACE 26149 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Scanning URL [jar:file:/multipom/appA/target/appA-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/App_A.class]
2017-03-18 11:23:23.430 TRACE 26149 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Ignored because not matching any filter: URL [jar:file:/multipom/appA/target/appA-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/App_A.class]
2017-03-18 11:23:24.084 DEBUG 26149 --- [ main] a.ConfigurationClassBeanDefinitionReader : Registering bean definition for @Bean method com.multipom.config.ApplicationConfig.hwBean()
案例 1:如果 'appA' 使用 'spring-boot-starter-parent' 作为父 POM(注意这里 'appB' 没有从 'appA' [=27] 中找到 'hwBean' =]
$ java -jar appB-0.0.1-SNAPSHOT.jar
2017-03-18 11:24:31.461 TRACE 26203 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Scanning URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/App_B.class]
2017-03-18 11:24:31.546 TRACE 26203 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Ignored because not matching any filter: URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/App_B.class]
案例 2:如果 'appA' 不使用 'spring-boot-starter-parent' 作为父 POM(注意这里 'appB' 确实从 'appA' 中找到 'hwBean'。
$ java -jar appB-0.0.1-SNAPSHOT.jar
2017-03-18 12:03:28.261 TRACE 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Scanning URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/App_B.class]
2017-03-18 12:03:28.316 TRACE 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Ignored because not matching any filter: URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/App_B.class]
2017-03-18 12:03:28.316 TRACE 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Scanning URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/appA-0.0.1-SNAPSHOT.jar!/com/multipom/App_A.class]
2017-03-18 12:03:28.324 DEBUG 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Identified candidate component class: URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/appA-0.0.1-SNAPSHOT.jar!/com/multipom/App_A.class]
2017-03-18 12:03:28.325 TRACE 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Scanning URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/appA-0.0.1-SNAPSHOT.jar!/com/multipom/config/ApplicationConfig.class]
2017-03-18 12:03:28.330 DEBUG 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Identified candidate component class: URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/appA-0.0.1-SNAPSHOT.jar!/com/multipom/config/ApplicationConfig.class]
2017-03-18 12:03:28.348 DEBUG 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning
2017-03-18 12:03:28.373 TRACE 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Scanning URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/App_B.class]
2017-03-18 12:03:28.384 DEBUG 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Identified candidate component class: URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/multipom/App_B.class]
2017-03-18 12:03:28.385 TRACE 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Scanning URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/appA-0.0.1-SNAPSHOT.jar!/com/multipom/App_A.class]
2017-03-18 12:03:28.388 TRACE 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Ignored because not matching any filter: URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/appA-0.0.1-SNAPSHOT.jar!/com/multipom/App_A.class]
2017-03-18 12:03:28.389 TRACE 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Scanning URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/appA-0.0.1-SNAPSHOT.jar!/com/multipom/config/ApplicationConfig.class]
2017-03-18 12:03:28.390 DEBUG 27097 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner : Identified candidate component class: URL [jar:file:/multipom/appB/target/appB-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/appA-0.0.1-SNAPSHOT.jar!/com/multipom/config/ApplicationConfig.class]
2017-03-18 12:03:29.123 DEBUG 27097 --- [ main] a.ConfigurationClassBeanDefinitionReader : Registering bean definition for @Bean method com.multipom.config.ApplicationConfig.hwBean()
问题是spring-boot-maven-plugin 打包依赖jar 的方式。在默认设置中,此插件将 jar 打包为一种特殊的可执行 jar 格式,将所有 类 置于 /BOOT-INF/classes/... 下。如果您的 jar 被用作另一个模块中的依赖项,则您不需要想要那个。相反,您的 jar 必须是一个普通的扁平 jar,这样所有包含的 beans 都可以被依赖的应用程序发现。解决方案是将以下内容添加到 spring-boot-maven-plugin
部分(在 appA/pom.xml 中):
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>