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")
条件评估取决于数据库中提供的值 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")