【问题标题】:How to use @ConditionalOnBean with @Qualifier in Spring Boot?如何在 Spring Boot 中使用@ConditionalOnBean 和@Qualifier?
【发布时间】:2022-12-11 16:22:12
【问题描述】:

目前,我有以下两个课程:

@Configuration
@Import(AssumeRoleSQSConfig.class)
public class AssumeRoleConfig {
    public static final DynamicStringProperty ROLE_ARN = DynamicPropertyFactory.getInstance()
            .getStringProperty("role.arn", null);
    public static final DynamicStringProperty ROLE_SESSION = DynamicPropertyFactory.getInstance()
            .getStringProperty("role.session.name", null);
    
    @Bean(name = "assumeRole")
    public AWSCredentialsProvider getCredentials() {
        if (ROLE_ARN.get() == null || ROLE_SESSION.get() == null) {
            return null;
        }
        ... omitted ...
    }
}

而且,我在 config.properties 中设置了这两个属性。

@Configuration
public class AssumeRoleSQSConfig {
    @Bean(name = "sqsAssumeBean")
    @ConditionalOnBean(name = "assumeRole")
    public AmazonSQSAsync sqsAssume(
        @Qualifier("assumeRole") AWSCredentialsProvider awsCredentials) {
        ... omitted ...
    }
}

我也有这两个默认 bean:

@Configuration
@Import(DefaultSQSConfig.class)
public class DefaultCredentialsConfig {
    @Bean
    @Primary
    public AWSCredentialsProvider defaultCred() {
        return new DefaultAWSCredentialsProviderChain();
    }
}
@Configuration
public class DefaultSQSConfig {
    @Bean(destroyMethod = "destroy")
    @Primary
    public AmazonSQSAsync defaultSQS() {
        ... omitted ...
    }
}

如果另一个类试图像这样访问“sqsAssumeBean”和“defaultSQS”:

@Configuration
@Import({DefaultCredentialsConfig.class, AssumeRoleConfig.class})
public class QueueConfig {
    
    private AmazonSQSAsync defaultSQS;
    private AmazonSQSAsync assumeRoleSQS;

    @Autowired
    public QueueConfig (
        @Qualifier("defaultSQS") AmazonSQSAsync defaultSQS,
        @Qualifier("sqsAssumeBean") AmazonSQSAsync assumeRoleSQS) {
        this.defaultSQS = defaultSQS;
        this.assumeRoleSQS = assumeRoleSQS;
    }
}

然后,我收到以下错误:

Error creating bean with name 'queueConfig' defined in ... QueueConfig.class 
Unsatisfied dependency expressed through constructor parameter 1; 
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.amazonaws.services.sqs.AmazonSQSAsync' available: 
expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value="sqsAssumeBean")}

Description:

Parameter 1 of constructor in QueueConfig required a bean of type 'com.amazonaws.services.sqs.AmazonSQSAsync' that could not be found.

The following candidates were found but could not be injected:
    - User-defined bean method 'defaultSQS' in 'DefaultSQSConfig'

到目前为止,据我了解,QueueConfig 构造函数查找 bean“sqsAssumeBean”,但找不到“assumeRole”bean,因为它尚未创建。因此,QueueConfig 构造函数查找“defaultSQS”bean 而不是“sqsAssumeBean”,但它无法注入,因为@Qualifier 正在专门查找“assumeRole”bean。

我调试了应用程序,发现 AssumeRoleConfig“getCredentials”方法甚至没有被调用。这意味着 AssumeRoleSQSConfig 甚至不尝试获取 bean“assumeRole”,但如果我删除 @ConditionalOnBean,它会尝试获取。 为什么@ConditionalOnBean 主动发现没有创建"assumeRole"bean 反而让创建"assumeRole"bean 如果为null 则主动声明没有"assumeRole"bean?谢谢!

(注意:我有 ROLE_ARN 和 ROLE_SESSION 动态属性。所以,我想做的是,如果 ROLE_ARN/ROLE_SESSION 动态属性未设置/为空,则不应创建“assumeRole”bean。这也应该有条件地不创建“sqsAssumeBean ”。这也应该有条件地不创建“queueConfig”bean。但是,目前,即使我设置了这两个动态属性,创建“assumeRole”bean 的方法也根本不会被调用。)

【问题讨论】:

  • 它可能适用于@Autowired(required = false)
  • 没有变化。我仍然得到同样的例外。

标签: spring spring-boot dependency-injection aws-java-sdk


【解决方案1】:

您遇到的问题是注入可选的依赖项。

实现它的首选方法有以下三种:

  1. 在参数级别使用org.springframework.lang.Nullable注解
  2. 使用java.util.Optional使参数可选
  3. 定义多个 @Autowired(required = false) 构造函数,只定义必需的参数

    Spring @Autowired Reference

【讨论】:

  • 我尝试了所有三个选项,但仍然没有创建“sqsAssumeBean”(我得到 NPE)。我认为我的问题有点不清楚。我编辑了它。我实际上希望在“sqsAssumeBean”之前创建“assumeRole”bean。但是,不想在“assumeRole”为空时创建“sqsAssumeBean”。但是,即使我设置了这两个动态属性(这意味着“assumeRole”bean 在创建时不应为 null),但根本不会调用创建“assumeRole”bean 的方法。因此,@ConditionalOnBean 认为没有“assumeRole”bean。我希望这有帮助。
  • 由于没有定义循环依赖关系,因此应该按常规顺序创建 bean。我建议检查配置 - @Import 注释是否对于该映射是必要的,以及 assumeRole bean 是否真的创建了。您还必须调试 getCredentials() 工厂方法以测试它是否正常工作。
【解决方案2】:

不确定是否有帮助,但您是否尝试过@AutoConfigureAfter@AutoConfigureBefore

【讨论】:

    猜你喜欢
    • 2018-10-21
    • 2015-07-07
    • 1970-01-01
    • 1970-01-01
    • 2017-05-04
    • 2018-08-06
    • 1970-01-01
    • 2017-05-15
    • 1970-01-01
    相关资源
    最近更新 更多