【问题标题】:@Conditional on bean initialization@Conditional on bean 初始化
【发布时间】:2017-07-07 20:12:47
【问题描述】:

我一直在寻找这个。

到目前为止,我发现this 博客非常有用,但并没有解决我的问题。

只有当flag 为真时,我才想@Autowired 一个bean,否则我希望它是null

用例:

如果其中一个数据库正在维护中,我不希望我的应用失败。

@Bean("sqlDatabase")
public Database getSqlDatabase(@Value("${datasource.sql.url}") String url,
        @Value("${datasource.sql.username}") String username, @Value("${datasource.sql.password}") String password,
        @Value("${datasource.poolsize.min}") int minPoolSize, @Value("${datasource.poolsize.max}") int maxPoolSize,
        @Value("${database.enable-sql}") boolean isSqlEnabled) {
    if (isSqlEnabled)
        return Database.builder().url(url).pool(minPoolSize, maxPoolSize).username(username).password(password)
                .build();
    else
        return null;
}

现在,在这种情况下,它会抛出错误,因为我不能 autowire a null bean。

我想使用@Conditional,但我的情况有点复杂。我已经需要更新所有 3 个数据库。如果条件不满足我只想skip其中一个。

【问题讨论】:

  • 我已经需要更新所有 3 个数据库。如果条件不满足,我只想跳过其中一个。。你能详细说明一下你的意思吗?
  • 我有一个涉及 3 个数据库的 Spring Boot 应用程序。我正在为它们创建 3 种不同的 bean。现在让我们说进行维护,我们要关闭一个数据库,我仍然需要休息 2。在博客的示例中。 EITHER-OR 确实不适用于我的情况。我只是不希望我的初始化因尝试连接超时而挂起。

标签: java spring spring-boot conditional autowired


【解决方案1】:

您可以使用配置文件。 每个数据库都有一个配置文件

  • db1
  • db2
  • db3

使用必须激活的配置文件来注释 bean 类或 bean 方法以使用该 bean,就像

@Profile("db1")
@Bean("db1")
public Database getSqlDatabase(...){...}       

当您启动您的应用程序时,只有在相关配置文件被激活时,才会创建带有 @Profile 注释的 bean。

您可以通过设置属性“spring.profiles.active”来激活配置文件。 激活 db1 和 db2 :

spring.profiles.active=db1,db3

您可以在属性文件中或作为命令行参数设置该属性。

配置文件为您提供了很大的灵活性,可以通过配置更改弹簧上下文

  • 您可以使用相同的配置文件注释许多 bean
  • 您可以使用配置文件注释配置类
  • 您可以使用配置文件特定的属性文件
  • 您可以在一个@Profile 注释中使用多个配置文件。将使用逻辑“或”,因此如果配置文件“db1”处于活动状态或配置文件“db2”处于活动状态,则将创建一个带有 @Profile("db1","db2") 注释的 bean
    • 如果您想要除“或”以外的其他内容,您可以使用@Conditional 来定义您自己的逻辑

请注意:如果您使用不使用组件扫描或xml配置,则bean类处的注解@Profile无效。您需要使用 @Profile 或整个配置类来注释 bean 方法。

【讨论】:

  • 对字段进行注释后会发生什么?不满足profile会为null吗?
  • 正如我所怀疑的,它将 bean 自动连接为 null。正是我需要的!我可以处理剩下的。非常感谢。我不必要地混淆了很多事情。 :)
【解决方案2】:

我们可以在initial component scan 期间利用@Conditional 属性来避免错误,同时基于环境属性进行初始化。

当环境db.enabled 属性为true 时,一个有效的用例是启用对存储库进行bean 初始化扫描

示例: https://javapapers.com/spring/spring-conditional-annotation/

条件帮助类

public class DocumentDBInitializerPresence implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        DocumentDBInitializerInfo employeeBeanConfig = null;
        try {
            employeeBeanConfig = (DocumentDBInitializerInfo)context.getBeanFactory().getBean("DocumentDBInitializerInfo");
        } catch(NoSuchBeanDefinitionException ex) {
            System.out.println("BEAN NOT FOUND:: " + employeeBeanConfig != null );
        }
        System.out.println("BEAN FOUND :: " + employeeBeanConfig != null );
        boolean matches = Boolean.valueOf(context.getEnvironment().getProperty("db.enabled"));
        System.out.println("CONFIG ENABLED :: " + employeeBeanConfig != null );
        return employeeBeanConfig != null && matches;
    }
}

在服务中使用

@Service
@RefreshScope
@Conditional(value= DocumentDBInitializerPresence.class)
public class RepositoryDocumentDB {

    private static Logger LOGGER = LoggerFactory.getLogger(RepositoryDocumentDB.class);

    public static final String DOCUMENT_DB_LOCAL_HOST = "localhost";
    DocumentDBInitializerInfo documentDbConfig;

    @Autowired
    public RepositoryDocumentDB(final DocumentDBInitializerInfo documentDbConfig) {
        this.documentDbConfig = documentDbConfig;
    }
}

如果您没有自动装配,这不会在应用程序启动时引发错误 RepositoryDocumentDB 任何地方,并且 db.enabled 设置为 false。

希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 2013-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-28
    • 2013-01-06
    • 2017-06-10
    • 2023-03-02
    • 1970-01-01
    相关资源
    最近更新 更多