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

Java 如果@Configuration类包含不可解析的类引用,Spring如何调用@Bean方法,java,spring,spring-boot,classloading,Java,Spring,Spring Boot,Classloading,Spring可以使用ClassReaders解析@Configuration类 假设我们有以下场景 我们有一个具有多个@Bean定义的自动配置类 其中一个@Bean传递了所有条件,而第二个@Bean传递了@ConditionalOnClass&类路径中不存在该类 @配置 类自定义配置{ @豆子 @ConditionalOnClass(String.class) 字符串knownClass(){ 回复“你好”; } @豆子 @ConditionalOnClass(MissingClass.clas

Spring可以使用
ClassReader
s解析
@Configuration

假设我们有以下场景

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

其中一个
@Bean
传递了所有条件,而第二个
@Bean
传递了
@ConditionalOnClass
&类路径中不存在该类

@配置
类自定义配置{
@豆子
@ConditionalOnClass(String.class)
字符串knownClass(){
回复“你好”;
}
@豆子
@ConditionalOnClass(MissingClass.class)
缺少类secondBean(){
返回新的MissingClass();
}
}
在这个场景中,我有几个问题

  • Spring引导自动配置是否将第一个bean注册到
    ApplicationContext
  • 如果(1)为true,在调试期间是否会命中第一个
    @Bean
    方法中的断点
  • 如果(2)为true,那么如何将
    *自动配置
    类加载到JVM中,因为该类将引用在类加载时无法解析的其他类(来自第二个@Bean)
  • 如果(2)为false,spring是否在运行时仅使用第一个
    @Bean
    方法生成类并调用该方法

  • 谢谢

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

    要回答您的具体问题:

  • 是的,只要可以加载配置类,就会注册第一个bean
  • 是的,在调试过程中应该命中第一个
    @Bean
    方法中的断点
  • 这取决于如何引用无法解析的类。如果它仅在
    @Bean
    方法的主体中使用,则该类应成功加载。如果在
    @Bean
    方法(通常是返回类型)的签名中使用了无法解析的类,则该类将无法加载
  • 不适用
  • 如上面链接的文档所述,建议使用一个单独的、可能嵌套的
    @Configuration
    类和一个类级条件,而不是担心第3节中描述的场景以及什么将起作用和不起作用。对于您的特定示例,如下所示:

    @Configuration
    class CustomConfiguration {
    
      @Bean
      @ConditionalOnClass(String.class)
      String knownClass() {
        return "Hello";
      }
    
      @Configuration
      @ConditionalOnClass(MissingClass.class)
      static class DoubtfulBeanConfiguration {
    
        @Bean
        MissingClass missingClass() {
          return new MissingClass();
        }
    
      }
    
    }
    
    上面的安迪回答了“如何使用”的问题,即如何使用图书馆。但在这个回答中,我试图回答为什么的问题

    这是我的理解

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

    • 此文件由基于
      @配置的插件生成
      下列类别
      
      org.springframework.boot.autoconfigure.EnableAutoConfiguration
      key 在
      /META-INF/spring.factories
      文件中,由
      spring boot自动配置处理器
      插件
    • 生成的文件包含
      @Configuration
      类级别的注释,例如
      @ConditionalOnClass
      @AutoConfigureBefore
      , e、 [t.c]
  • Spring构建关于从上述属性文件检索到的每个
    @Configuration
    类的元数据
  • Spring然后根据当前类路径和bean工厂评估所有
    @Configuration
    类级条件,包括
    @ConditionalOnClass
    。如果条件成功,它将使用标准java类加载加载
    @Configuration
  • 如果我们将
    @ConditionalOnClass(MissingClass.class)
    保持在
    @Configuration
    级别,那么如果类级别的条件没有计算为true,比如类不在类路径中,spring就不会加载该类
  • 但是如果我们将
    @ConditionalOnClass(MissingClass.class)
    保持在
    @Bean
    级别,spring将尝试加载
    @Configuration
    类(假设
    @Configuration
    类级别的所有条件都得到满足)&我们将在类加载期间得到
    NoClassDefFoundError
  • 总的来说,由于这个原因,我们需要遵循@Andy解决方案

    @安迪

    如果您能就Spring是否是以这种方式在内部实现了
    @ConditionalOnClass
    功能给出您的看法,我们将不胜感激


    谢谢

    用一个示例更新了问题我相信我示例中的示例将抛出NoClassDefFound Error是的,它将抛出NoClassDefFound Error。因此,建议不要做你的例子正在做的事情。我添加了一个例子,以及你对问题本身提出的解决方案。若它是正确的,你们能把它加到你们的答案中吗?这样我就可以把它从问题中去掉。谢谢你的帮助!!我已经添加了一个具体的例子,说明事情应该如何组织。