如何构建基于数据库的 Spring Boot 环境/属性源? [英] How can I build a database-based Spring Boot environment / property source?

查看:49
本文介绍了如何构建基于数据库的 Spring Boot 环境/属性源?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目标是在一个包含键 & 的环境中运行 Spring Boot 应用程序.由数据库连接 (DataSource) 加载和生成的值.

The goal is running Spring Boot application with an Environment containing keys & values loaded and generated by a database connection (DataSource).

或者,更抽象的定义:虽然只应首选文件配置(更快、更容易、更宽容,...),但有时您会发现需要基于非静态文件的配置的用例.

Or, more abstract defined: While a configuration by files only should be preferred (faster, easier, more tolerant, ...), sometimes you will find use cases where a non-static files based configuration is required.

Spring 3.1 引入了Environment,它实际上是一个属性解析器(扩展了PropertyResolver)并且基于对象列表PropertySource.这样的源是属性(文件或对象)、地图或其他东西的包装器/适配器.看起来真的是这样的获取方式.

Spring 3.1 introduces Environment which is actually a property resolver (extends PropertyResolver) and is based on a list of objects PropertySource. Such a source is a wrapper/adapter for a properties (file or object), a map or something else. It really looks like this is the way how to get.

Properties properties = new Properties();
properties.put("mykey", "in-config");
PropertiesPropertySource propertySource = new PropertiesPropertySource("myProperties", properties);

然而,这不能在@Configuration 类中完成,因为它必须在配置阶段可用.想想类似的事情

However, this cannot be done in @Configuration classes since it must be available for the configuration phase. Think about something like

@Bean public MyService myService() {
  if ("one".equals(env.getProperty("key")) {
    return new OneService();
  } else {
    return new AnotherService();
  }
}

// alternatively via
@Value("${key}")
private String serviceKey;

此外,最近的 Spring 版本也支持 Condition.

Additionally, the more recent Spring releases support Condition as well.

使用 OneCondition 就像

public class OneCondition implements Condition {
  @Override
  public boolean matches(final ConditionContext context, final AnnotatedTypeMetadata metadata) {
    return "one".equals(context.getEnvironment().getProperty("key"));
  }
}

可以像这样使用

@Bean
@Conditional(OneCondition.class)
public MyService myService() {
    return new OneService();
}

<小时>

我的非工作想法:


My non working ideas:

选项 1:@PropertySource

相应的注解处理器只处理文件.这很好,但不适用于此用例.

The corresponding annotation processor handles files only. This is fine, but not for this use case.

选项 2:PropertySourcesPlaceholderConfigurer

具有自定义属性源的示例是

An example with a custom property source would be

@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() throws IOException {
  PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer();
  pspc.setIgnoreUnresolvablePlaceholders(Boolean.TRUE);

  // create a custom property source and apply into pspc
  MutablePropertySources propertySources = new MutablePropertySources();
  Properties properties = new Properties();
  properties.put("key", "myvalue");
  final PropertiesPropertySource propertySource = new PropertiesPropertySource("pspc", properties);
  propertySources.addFirst(propertySource);
  pspc.setPropertySources(propertySources);

  pspc.setLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:application.properties"));
    return pspc;
}

然而,这只配置占位符(即@Value.任何environment.getProperty()都不会获利.

However, this only configures the placeholders (i.e. @Value. Any environment.getProperty() will not profit.

这或多或少与选项 1 相同(更少的魔法,更多的选项).

This is more or less the same as Option 1 (less magic, more options).

你知道更好的选择吗?理想情况下,该解决方案将使用上下文数据源.然而,这在概念上是一个问题,因为数据源 bean 创建依赖于属性本身......

Do you know a better option? Ideally, the solution would use the context datasource. However, this is conceptually an issue since the datasource bean creation relies on properties itself...

推荐答案

Spring Boot 为这个早期处理步骤提供了一些不同的扩展点:http://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-boot-application.html#howto-customize-the-environment-or-application-context

Spring Boot provides some different extensions point for this early processing step: http://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-boot-application.html#howto-customize-the-environment-or-application-context

在内部,这些选项是通过标准 Spring ApplicationContextInitializer 的实现实现的.

Internally, these options are realised with implementations of standard Spring ApplicationContextInitializer.

根据源的优先级,键/值将在 environment.getProperty() 以及属性占位符中可用.

Depending on the priority of the source, the key/value will be available both in environment.getProperty() as well in property placeholders.

因为这些是预配置上下文侦听器,所以没有其他 bean 可用,例如 DataSource.因此,如果要从数据库中读取属性,则必须手动构建数据源和连接(最终是单独的数据源连接查找).

Because these is a pre-config-context listeners, no other beans are available, like a DataSource. So if the properties should be read from a database, the datasource and connection have to be build manually (eventually a separated datasource connection lookup).

选项:ApplicationEnvironmentPreparedEvent 的 ApplicationListener

构建使用 ApplicationEnvironmentPreparedEvents 和

META-INF/spring.factories 和 key org.springframework.context.ApplicationListener

- 或 -

使用SpringApplicationBuilder:

new SpringApplicationBuilder(App.class)
        .listeners(new MyListener())
        .run(args);

示例

public class MyListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
  @Override
  public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
    final ConfigurableEnvironment env = event.getEnvironment();
    final Properties props = loadPropertiesFromDatabaseOrSo();
    final PropertiesPropertySource source = new PropertiesPropertySource("myProps", props);
    environment.getPropertySources().addFirst(source);
  }
}

参考:http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-spring-application.html#boot-features-application-events-和-听众

选项:SpringApplicationRunListener

除了特殊事件之外,还有一个更通用的事件侦听器,其中包含多种类型事件的钩子.

Besides the special event, there is also a more general event listener containing hooks for several types of events.

构建SpringApplicationRunListener 的实现,并在META-INF/spring.factories 和键org.springframework.boot.SpringApplicationRunListener 中注册它.

Build an implementation of SpringApplicationRunListener and register it in META-INF/spring.factories and the key org.springframework.boot.SpringApplicationRunListener.

示例

public class MyAppRunListener implements SpringApplicationRunListener {

  // this constructor is required!
  public MyAppRunListener(SpringApplication application, String... args) {}

  @Override
  public void environmentPrepared(final ConfigurableEnvironment environment) {

    MutablePropertySources propertySources = environment.getPropertySources();

    Properties props = loadPropertiesFromDatabaseOrSo();
    PropertiesPropertySource propertySource = new PropertiesPropertySource("myProps", props);
    propertySources.addFirst(propertySource);
  }

  // and some empty method stubs of the interface…

}

参考:http://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-boot-application.html#howto-customize-the-环境或应用程序上下文

选项:ApplicationContextInitializer

这是所有非 Boot"Spring 开发人员的老朋友.然而,SpringApplication 模拟了一个配置——起初.

This is an old friend for all "non Boot" Spring developers. However, SpringApplication mocks a configuration away -- at first.

构建 ApplicationContextInitializer

META-INF/spring.factories 和 key org.springframework.context.ApplicationContextInitializer 中注册.

register it in META-INF/spring.factories and the key org.springframework.context.ApplicationContextInitializer.

- 或 -

使用SpringApplicationBuilder:

new SpringApplicationBuilder(App.class)
        .initializers(new MyContextInitializer())
        .run(args);

示例

public class MyContextInitializer implements ApplicationContextInitializer {
  @Override
  public void initialize(final ConfigurableApplicationContext context) {
    ConfigurableEnvironment environment = context.getEnvironment();

    MutablePropertySources propertySources = environment.getPropertySources();

    Properties props = loadPropertiesFromDatabaseOrSo();
    PropertiesPropertySource propertySource = new PropertiesPropertySource("myProps", props);
    propertySources.addFirst(propertySource);
  }

}

这篇关于如何构建基于数据库的 Spring Boot 环境/属性源?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆