Spring @Conditional 基于数据库中的值 table

Spring @Conditional based on a value in database table

条件评估取决于数据库中提供的值 table

@Component
public class XYZCondition implements Condition{

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
              //based on value defined in DB should return true/false
    }

}

由于条件执行的很早,无法获取数据库值 有没有其他方法可以实现此目的?

嗯,也许您可​​以只创建一个配置 Class 并注入您的存储库,然后创建一个 Bean。然后在 bean 方法内部从数据库和 return 条件实例中获取值。像这样

@Configuration
public class Config {

@Autowired  
private Repository repository;

@Bean
public Interface interface(){
  boolean val = reposiory.getDBValue();
  if(val)
    return new Impl1();
  else
    return new Impl2();
  }
}

数据库值可以在应用程序工作期间更改,但重新加载应用程序上下文似乎不是一个好主意。 所以我建议使用配置属性来选择哪些 bean 应该在上下文中可用。

此外,还有一个 Spring Cloud Config 允许您将配置存储在 git 或其他一些存储中。一旦配置更改,其消费者可能会重新启动上下文。 看起来也值得一谈。

好吧,您正在尝试做一些不能很好地映射到 spring 以这种形式启动的事情。

我建议稍微更改一下要求:

与其尝试在自定义条件下访问数据库,不如创建自定义配置源并将 属性 从数据库加载到环境中,以便稍后在启动过程中评估条件时, 具有关联值(之前从数据库解析)的 属性 已经可用。

遵循这种方法的例子有: - Spring 从 "remote" 配置服务读取配置属性的启动云配置(通过 REST) - Spring 启动 consul 集成(显然是从 consul 读取的)

这种方法更 spring 友好,并且可以避免应用程序多次调用数据库(如果您有 100 个具有此自定义条件的 bean 会怎么样)- 它会执行 100 次查询吗?

现在,这可能意味着您不需要自定义条件 - 可能 属性 上 @Condition

另一个警告是您将无法使用 JPA/Spring 数据来加载此 属性,可能您必须在此处使用普通 JDBC。

遗憾的是你不能在条件中注入很多东西:所以尝试使用普通 url 并手动连接到服务器, 但在我的例子中这不起作用,因为我有将相同配置值添加到数据库中的飞路迁移(先有鸡还是先有蛋的问题)

class EnableXXXCondition implements Condition {
    private Environment environment;

    @SneakyThrows
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        environment = context.getBeanFactory().getBean(Environment.class);

        final String url = environment.getProperty("spring.datasource.url");
        final String user = environment.getProperty("spring.datasource.username");
        final String password = environment.getProperty("spring.datasource.password");

        String x;

        //we have problems with flyway before
        try (Connection connection = DriverManager.getConnection(url, user, password)) {
            try (Statement statement = connection.createStatement()) {
                try (final ResultSet resultSet = statement.executeQuery("select x from y")) {
                    resultSet.next();
                    x = resultSet.getString("x");
                }
            }
        }

        return Boolean.valueOf(x);
    }
}

您可以尝试在您的配置文件中定义您的条件并像下面这样使用它:

@ConditionalOnProperty(name="filter.enabled", havingValue="true")