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

时间:2019-02-05 14:14:19

标签: java spring spring-boot classloading

Spring可以使用@Configuration s来解析ClassReader

假设我们有以下情况

我们有一个带有多个@Bean定义的自动配置类

其中一个@Bean已通过所有条件,而第二个@Bean具有@ConditionalOnClass并且该类不在类路径中

@Configuration
class CustomConfiguration {
  @Bean
  @ConditionalOnClass(String.class)
  String knownClass() {
    return "Hello";
  }

  @Bean
  @ConditionalOnClass(MissingClass.class)
  MissingClass secondBean() {
    return new MissingClass();
  }
}

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

  1. Spring Boot自动配置是否将第一个bean注册到ApplicationContext中?
  2. 如果(1)为true,在调试过程中是否会在第一个@Bean方法中遇到我的断点
  3. 如果(2)为true,*AutoConfiguration类将如何加载到JVM中,因为此类将引用其他类(来自第二个@Bean),这些类在类加载时无法解析
  4. 如果(2)为false,spring是否在运行时仅使用第一个@Bean方法生成一个类并调用该方法?

谢谢

2 个答案:

答案 0 :(得分:3)

通常来说,出于这个确切原因,您应该避免在@ConditionalOnClass方法上使用@Beanreference documentation涵盖了这种情况,建议使用单独的@Configuration类来隔离@ConditionalOnClass条件。

要回答您的特定问题:

  1. 是的,只要可以加载配置类,就会注册第一个bean
  2. 是的,在调试过程中应在第一个@Bean方法中设置一个断点
  3. 这取决于如何引用无法解析的类。如果仅在@Bean方法的主体内使用它,则该类应成功加载。如果在@Bean方法的签名中使用了无法解析的类(通常是返回类型),则该类将无法加载。
  4. 不适用

如上面链接的文档中所述,建议不要担心3中描述的场景以及什么会起作用,什么不起作用,建议使用带有类级别条件的单独的,可能嵌套的@Configuration类方法。对于您的特定示例,应如下所示:

@Configuration
class CustomConfiguration {

  @Bean
  @ConditionalOnClass(String.class)
  String knownClass() {
    return "Hello";
  }

  @Configuration
  @ConditionalOnClass(MissingClass.class)
  static class DoubtfulBeanConfiguration {

    @Bean
    MissingClass missingClass() {
      return new MissingClass();
    }

  }

}

答案 1 :(得分:0)

上面的Andy回答了“如何提问”,即如何使用该库。但是在这个答案中,我试图回答为什么这个问题

这是我的理解

  1. Spring从类路径的/META-INF/spring-autoconfigure-metadata.properties中读取自动配置文件元数据(spring-boot-autoconfigure中存在一个这样的文件)

    • 此文件是由基于@Configuration的插件生成的 列出的课程 org.springframework.boot.autoconfigure.EnableAutoConfiguration/META-INF/spring.factories插件在spring-boot-autoconfigure-processor文件中添加
    • 生成的文件包含@Configuration类级别的注释,例如@ConditionalOnClass@AutoConfigureBefore, e.t.c]
  2. Spring为从上述属性文件中检索的每个@Configuration类构建元数据
  3. 然后,
  4. Spring根据当前的classpath和bean工厂评估所有@Configuration类级别的条件,包括@ConditionalOnClass。如果条件成功,它将使用标准java类加载来加载@Configuration
  5. 如果我们将@ConditionalOnClass(MissingClass.class)保持在@Configuration级别,则在类级别条件未评估为true的情况下,spring不会简单地将类加载到配置类中,例如,如果该类不在classpath中
  6. 但是如果我们将@ConditionalOnClass(MissingClass.class)保持在@Bean级别,spring将尝试加载我们的@Configuration类(假设满足@Configuration类级别的所有条件)并且我们将在类加载期间获取NoClassDefFoundError

总体而言,由于这个原因,我们需要遵循@Andy解决方案

@安迪

请您欣赏一下Spring是否内部实现了@ConditionalOnClass功能的视图

谢谢