如果@Configuration class 包含无法解析的 class 引用,Spring 如何调用 @Bean 方法

How Spring invokes @Bean methods if @Configuration class contains unresolvable class refs

Spring 可以使用 ClassReaders

解析 @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();
  }
}

在这种情况下,我有几个问题

  1. Spring 引导自动配置是否将第一个 bean 注册到 ApplicationContext
  2. 如果 (1) 为真,我在 first @Bean 方法中的断点会在调试期间命中吗
  3. 如果 (2) 为真,*AutoConfiguration class 如何加载到 JVM 中,因为此 class 将引用其他 classes(来自第二个@ Bean) 无法在 class 加载时间
  4. 解析
  5. 如果 (2) 为假,spring 会在运行时仅使用第一个 @Bean 方法生成 class 并调用该方法吗?

谢谢

一般来说,出于这个确切原因,您应该避免在 @Bean 方法上使用 @ConditionalOnClassreference documentation 中介绍了这种情况,建议使用单独的 @Configuration class 来隔离 @ConditionalOnClass 条件。

回答您的具体问题:

  1. 是的,第一个bean只要配置class能加载就注册
  2. 是的,第一个 @Bean 方法中的断点应该在调试期间命中
  3. 要看无法解析的class是怎么引用的。如果它仅在 @Bean 方法的主体内使用,则 class 应该会成功加载。如果无法解析的class用于@Bean方法的签名(通常是return类型),class将无法加载。
  4. 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",即如何使用库。但在这个答案中,我试图回答为什么问题

这是我的理解

  1. 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 插件
    • 生成的文件包含@Configurationclass级注释如@ConditionalOnClass@AutoConfigureBefore、 e.t.c]
  2. Spring 构建关于从上述属性文件
  3. 中检索到的每个 @Configuration classes 的元数据
  4. Spring 然后根据当前 class 路径和 bean 工厂评估所有 @Configuration class 级别条件,包括 @ConditionalOnClass。如果条件成功,它将使用标准 java class loading
  5. 加载 @Configuration class
  6. 如果我们将@ConditionalOnClass(MissingClass.class)保持在@Configuration级别,spring根本不会加载class加载配置class如果class 级别条件不计算为真,比如 class 不在 classpath
  7. 但是如果我们将 @ConditionalOnClass(MissingClass.class) 保持在 @Bean 级别,spring 将尝试加载我们的 @Configuration class(假设所有条件都在 @Configuration class level 满足) & 我们将在 class load
  8. 期间得到 NoClassDefFoundError

总的来说,由于这个原因,我们需要遵循@Andy 的解决方案

@安迪

如果您能就这是否是 Spring 内部实现 @ConditionalOnClass 功能的方式发表您的看法,我们将不胜感激

谢谢