如果@Configuration class 包含无法解析的 class 引用,Spring 如何调用 @Bean 方法
How Spring invokes @Bean methods if @Configuration class contains unresolvable class refs
Spring 可以使用 ClassReader
s
解析 @Configuration
classes
假设我们有以下场景
我们有一个具有多个 @Bean
定义的自动配置 class
其中一个 @Bean
满足所有条件,而第二个 @Bean
满足 @ConditionalOnClass
且 class 不在 class 路径中
@Configuration
class CustomConfiguration {
@Bean
@ConditionalOnClass(String.class)
String knownClass() {
return "Hello";
}
@Bean
@ConditionalOnClass(MissingClass.class)
MissingClass secondBean() {
return new MissingClass();
}
}
在这种情况下,我有几个问题
- Spring 引导自动配置是否将第一个 bean 注册到
ApplicationContext
?
- 如果 (1) 为真,我在 first
@Bean
方法中的断点会在调试期间命中吗
- 如果 (2) 为真,
*AutoConfiguration
class 如何加载到 JVM 中,因为此 class 将引用其他 classes(来自第二个@ Bean) 无法在 class 加载时间 解析
- 如果 (2) 为假,spring 会在运行时仅使用第一个
@Bean
方法生成 class 并调用该方法吗?
谢谢
一般来说,出于这个确切原因,您应该避免在 @Bean
方法上使用 @ConditionalOnClass
。 reference documentation 中介绍了这种情况,建议使用单独的 @Configuration
class 来隔离 @ConditionalOnClass
条件。
回答您的具体问题:
- 是的,第一个bean只要配置class能加载就注册
- 是的,第一个
@Bean
方法中的断点应该在调试期间命中
- 要看无法解析的class是怎么引用的。如果它仅在
@Bean
方法的主体内使用,则 class 应该会成功加载。如果无法解析的class用于@Bean
方法的签名(通常是return类型),class将无法加载。
- N/A
如上面链接的文档中所述,与其担心 3 中描述的场景以及哪些会起作用,哪些不会起作用,使用单独的、可能嵌套的 @Configuration
class 和 class级条件是推荐的方法。对于您的具体示例,它看起来像这样:
@Configuration
class CustomConfiguration {
@Bean
@ConditionalOnClass(String.class)
String knownClass() {
return "Hello";
}
@Configuration
@ConditionalOnClass(MissingClass.class)
static class DoubtfulBeanConfiguration {
@Bean
MissingClass missingClass() {
return new MissingClass();
}
}
}
Andy 上面回答了 "how question",即如何使用库。但在这个答案中,我试图回答为什么问题
这是我的理解
Spring 从 class 路径读取 /META-INF/spring-autoconfigure-metadata.properties
的自动配置文件元数据(一个这样的文件存在于 spring-boot-autoconfigure
中)
- 这个文件是由基于
@Configuration
的插件生成的
class列在
org.springframework.boot.autoconfigure.EnableAutoConfiguration
键
在 /META-INF/spring.factories
文件中由 spring-boot-autoconfigure-processor
插件
- 生成的文件包含
@Configuration
class级注释如@ConditionalOnClass
、@AutoConfigureBefore
、
e.t.c]
- Spring 构建关于从上述属性文件
中检索到的每个 @Configuration
classes 的元数据
- Spring 然后根据当前 class 路径和 bean 工厂评估所有
@Configuration
class 级别条件,包括 @ConditionalOnClass
。如果条件成功,它将使用标准 java class loading 加载 @Configuration
class
- 如果我们将
@ConditionalOnClass(MissingClass.class)
保持在@Configuration
级别,spring根本不会加载class加载配置class如果class 级别条件不计算为真,比如 class 不在 classpath 中
- 但是如果我们将
@ConditionalOnClass(MissingClass.class)
保持在 @Bean
级别,spring 将尝试加载我们的 @Configuration
class(假设所有条件都在 @Configuration
class level 满足) & 我们将在 class load 期间得到 NoClassDefFoundError
总的来说,由于这个原因,我们需要遵循@Andy 的解决方案
@安迪
如果您能就这是否是 Spring 内部实现 @ConditionalOnClass
功能的方式发表您的看法,我们将不胜感激
谢谢
Spring 可以使用 ClassReader
s
@Configuration
classes
假设我们有以下场景
我们有一个具有多个 @Bean
定义的自动配置 class
其中一个 @Bean
满足所有条件,而第二个 @Bean
满足 @ConditionalOnClass
且 class 不在 class 路径中
@Configuration
class CustomConfiguration {
@Bean
@ConditionalOnClass(String.class)
String knownClass() {
return "Hello";
}
@Bean
@ConditionalOnClass(MissingClass.class)
MissingClass secondBean() {
return new MissingClass();
}
}
在这种情况下,我有几个问题
- Spring 引导自动配置是否将第一个 bean 注册到
ApplicationContext
? - 如果 (1) 为真,我在 first
@Bean
方法中的断点会在调试期间命中吗 - 如果 (2) 为真,
*AutoConfiguration
class 如何加载到 JVM 中,因为此 class 将引用其他 classes(来自第二个@ Bean) 无法在 class 加载时间 解析
- 如果 (2) 为假,spring 会在运行时仅使用第一个
@Bean
方法生成 class 并调用该方法吗?
谢谢
一般来说,出于这个确切原因,您应该避免在 @Bean
方法上使用 @ConditionalOnClass
。 reference documentation 中介绍了这种情况,建议使用单独的 @Configuration
class 来隔离 @ConditionalOnClass
条件。
回答您的具体问题:
- 是的,第一个bean只要配置class能加载就注册
- 是的,第一个
@Bean
方法中的断点应该在调试期间命中 - 要看无法解析的class是怎么引用的。如果它仅在
@Bean
方法的主体内使用,则 class 应该会成功加载。如果无法解析的class用于@Bean
方法的签名(通常是return类型),class将无法加载。 - N/A
如上面链接的文档中所述,与其担心 3 中描述的场景以及哪些会起作用,哪些不会起作用,使用单独的、可能嵌套的 @Configuration
class 和 class级条件是推荐的方法。对于您的具体示例,它看起来像这样:
@Configuration
class CustomConfiguration {
@Bean
@ConditionalOnClass(String.class)
String knownClass() {
return "Hello";
}
@Configuration
@ConditionalOnClass(MissingClass.class)
static class DoubtfulBeanConfiguration {
@Bean
MissingClass missingClass() {
return new MissingClass();
}
}
}
Andy 上面回答了 "how question",即如何使用库。但在这个答案中,我试图回答为什么问题
这是我的理解
Spring 从 class 路径读取
/META-INF/spring-autoconfigure-metadata.properties
的自动配置文件元数据(一个这样的文件存在于spring-boot-autoconfigure
中)- 这个文件是由基于
@Configuration
的插件生成的 class列在org.springframework.boot.autoconfigure.EnableAutoConfiguration
键 在/META-INF/spring.factories
文件中由spring-boot-autoconfigure-processor
插件 - 生成的文件包含
@Configuration
class级注释如@ConditionalOnClass
、@AutoConfigureBefore
、 e.t.c]
- 这个文件是由基于
- Spring 构建关于从上述属性文件 中检索到的每个
- Spring 然后根据当前 class 路径和 bean 工厂评估所有
@Configuration
class 级别条件,包括@ConditionalOnClass
。如果条件成功,它将使用标准 java class loading 加载 - 如果我们将
@ConditionalOnClass(MissingClass.class)
保持在@Configuration
级别,spring根本不会加载class加载配置class如果class 级别条件不计算为真,比如 class 不在 classpath 中
- 但是如果我们将
@ConditionalOnClass(MissingClass.class)
保持在@Bean
级别,spring 将尝试加载我们的@Configuration
class(假设所有条件都在@Configuration
class level 满足) & 我们将在 class load 期间得到
@Configuration
classes 的元数据
@Configuration
class
NoClassDefFoundError
总的来说,由于这个原因,我们需要遵循@Andy 的解决方案
@安迪
如果您能就这是否是 Spring 内部实现 @ConditionalOnClass
功能的方式发表您的看法,我们将不胜感激
谢谢