Spring Boot:使用database和application.properties进行配置

我需要在数据库中保存Spring Boot应用程序的配置。

是否可以将数据库信息存储在application.properties并使用它们连接到数据库并从那里检索所有其他属性?

所以我的application.properties看起来像:

 spring.datasource.url=jdbc:sqlserver://localhost:1433;databaseName=mydb spring.datasource.username=user spring.datasource.password=123456 spring.jpa.database-platform=org.hibernate.dialect.SQLServer2012Dialect 

其他配置将从数据库中获取,如下所示:

 @Configuration @PropertySource(value = {"classpath:application.properties"}) public class ConfigurationPropertySource { private final ConfigurationRepository configurationRepository; @Autowired public ConfigurationPropertySource(ConfigurationRepository configurationRepository) { this.configurationRepository = configurationRepository; } public String getValue(String key) { ApplicationConfiguration configuration = configurationRepository.findOne(key); return configuration.getValue(); } } 

使用ApplicationConfiguration作为Entity

但Spring Boot无法从数据库中获取配置。

您可以锻炼的一种可能解决方案是使用ConfigurableEnvironment并重新加载和添加属性。

 @Configuration public class ConfigurationPropertySource { private ConfigurableEnvironment env; private final ConfigurationRepository configurationRepository; @Autowired public ConfigurationPropertySource(ConfigurationRepository configurationRepository) { this.configurationRepository = configurationRepository; } @Autowired public void setConfigurableEnvironment(ConfigurableEnvironment env) { this.env = env; } @PostConstruct public void init() { MutablePropertySources propertySources = env.getPropertySources(); Map myMap = new HashMap(); //from configurationRepository get values and fill mapp propertySources.addFirst(new MapPropertySource("MY_MAP", myMap)); } } 

遗憾的是,我还没有针对此问题的解决方案,但我现在使用以下解决方法(需要在配置更改时重新启动其他应用程序)。

 @Component public class ApplicationConfiguration { @Autowired private ConfigurationRepository configurationRepository; @Autowired private ResourceLoader resourceLoader; @PostConstruct protected void initialize() { updateConfiguration(); } private void updateConfiguration() { Properties properties = new Properties(); List configurations = configurationRepository.findAll(); configurations.forEach((configuration) -> { properties.setProperty(configuration.getKey(), configuration.getValue()); }); Resource propertiesResource = resourceLoader.getResource("classpath:configuration.properties"); try (OutputStream out = new BufferedOutputStream(new FileOutputStream(propertiesResource.getFile()))) { properties.store(out, null); } catch (IOException | ClassCastException | NullPointerException ex) { // Handle error } } } 

我从数据库加载配置并将其写入另一个属性文件。 该文件可与@PropertySource("classpath:configuration.properties")

另一种选择是使用ApplicationContextInitializer,其优点是能够直接使用@Value并且还能够收缩属性的优先级。

 import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.HashMap; import java.util.Map; import javax.sql.DataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySource; public class ReadDBPropertiesInitializer implements ApplicationContextInitializer { private static final Logger LOG = LoggerFactory.getLogger(ReadDBPropertiesInitializer.class); /** * Name of the custom property source added by this post processor class */ private static final String PROPERTY_SOURCE_NAME = "databaseProperties"; @Override public void initialize(ConfigurableApplicationContext applicationContext) { ConfigurableEnvironment configEnv = ((ConfigurableEnvironment) applicationContext.getEnvironment()); LOG.info("Load properties from database"); Map propertySource = new HashMap<>(); try { final String url = getEnv(configEnv, "spring.datasource.url"); String driverClassName = getProperty(configEnv, "spring.datasource.driver-class-name"); final String username = getEnv(configEnv, "spring.datasource.username"); final String password = getEnv(configEnv, "spring.datasource.password"); DataSource ds = DataSourceBuilder.create().url(url).username(username).password(password) .driverClassName(driverClassName).build(); // Fetch all properties PreparedStatement preparedStatement = ds.getConnection() .prepareStatement("SELECT config_key as name, config_value as value, config_label as label FROM TB_CONFIGURATION"); ResultSet rs = preparedStatement.executeQuery(); // Populate all properties into the property source while (rs.next()) { final String propName = rs.getString("name"); final String propValue = rs.getString("value"); final String propLabel = rs.getString("label"); LOG.info(String.format("Property: %s | Label: %s", propName, propLabel)); LOG.info(String.format("Value: %s", propValue)); propertySource.put(propName, propValue); } // Create a custom property source with the highest precedence and add it to // Spring Environment applicationContext.getEnvironment().getPropertySources() .addFirst(new MapPropertySource(PROPERTY_SOURCE_NAME, propertySource)); } catch (Exception e) { throw new RuntimeException("Error fetching properties from db"); } } private String getEnv(ConfigurableEnvironment configEnv, final String property) { MutablePropertySources propertySources = configEnv.getPropertySources(); PropertySource appConfigProp = propertySources.get("applicationConfigurationProperties"); return System.getenv().get(((String) appConfigProp.getProperty(property)).replace("${", "").replace("}", "")); } private String getProperty(ConfigurableEnvironment configEnv, final String property) { MutablePropertySources propertySources = configEnv.getPropertySources(); PropertySource appConfigProp = propertySources.get("applicationConfigurationProperties"); return (String) appConfigProp.getProperty(property); } 

参考文献:

  1. https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-customize-the-environment-or-application-context
  2. https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config

PS:这段代码是我在互联网上找到的其他代码的混合。 学分完全来自作者。 很抱歉无法找到他们的链接,在你让他们工作之前,已经有很多测试。 但是如果你发现这与其他发现的类似,你可以肯定这只是一个推导。 ;)

环境:

  1. Java:OpenJDK运行时环境(版本1.8.0_171-8u171-b11-0ubuntu0.16.04.1-b11)
  2. spring:4.3.11
  3. Spring Boot:1.5.7
  4. Hibernate核心:5.2.10-最终版

您需要的是Spring Cloud Config: https : //cloud.spring.io/spring-cloud-config/

它将使用ad git repository(= database)和所有属性文件。 在启动时,它将获得最新版本,并使用它来启动应用程序。

在运行时更改配置时,可以刷新,无需重新启动!