SpringBoot @Bean 和 @ConditionalOnClass 同时使用(如何实现存在指定类型时才注入某个 Bean)

有时候会希望存在指定类型时才注入某个 Bean(或者某个类型不存在时才注入某个 Bean):

@AutoConfiguration
public class MyAutoConfiguration {
  @Bean
  @ConditionalOnClass(MyService.class)
  public MyConditionalBean statistics() {
      return new MyConditionalBean();
  }

  // @Bean
  // @ConditionalOnMissingBean(MyService.class)
  // public MyConditionalBean statistics() {
  //     return new MyConditionalBean();
  // }
}

但是如果按照上述代码,当MyService不存在的时候,程序会直接找不到类,导致程序无法启动。

你会发现@ConditionalOnClass用在被@Configuration标注的类上,即使指定的类不存在,程序也会正常启动。但是像上面那样就不行。

这是因为和@Configuration一起使用@ConditionalOnClass时,其注解信息通过 ASM 解析,但是在处理和@Bean一起用的@ConditionalOnClass时,所在的配置类已经被 JVM 加载了,也就是加载在解析的前面,而要加载成功,首先要能够找到@ConditionalOnClass所指明的类。


解决方法

  1. 指定全类名

    @Bean
    @ConditionalOnClass(name ="com.example.MyService")
    public MyConditionalBean statistics() {
        return new MyConditionalBean();
    }
    
  2. 内嵌配置类

    @AutoConfiguration
    public class MyAutoConfiguration {
      @Configuration
      @ConditionalOnClass(MyService.class)
      public class MyConfiguration {
          @Bean
          public MyConditionalBean statistics() {
              return new MyConditionalBean();
          }
      }
    }
    
  3. 创建一个单独的配置类,其实和内置配置类类似,只是将配置类拿了出来

    @AutoConfiguration
    @ConditionalOnClass(MyService.class)
    public class MyAutoConfiguration2 {
      @Bean
      public MyConditionalBean statistics() {
          return new MyConditionalBean();
      }
    }
    

参考:

Creating Your Own Auto-configuration :: Spring Boot

java - How does spring-boot @ConditionalOnClass work? - Stack Overflow

posted @ 2025-01-01 17:32  Higurashi-kagome  阅读(86)  评论(0)    收藏  举报