Spring Boot:使用数据库和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 并没有从数据库中获取配置。

原文由 deve 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 837
1 个回答

我知道这是一个老问题,但我在寻找解决方案时偶然发现了它,并想分享一种对我有用的方法。

一种方法是使用 org.springframework.boot.env.EnvironmentPostProcessor 的实现。下面是我使用的一个实现,它对我来说效果很好。您必须使用以下条目将 META-INF/spring.factories 文件添加到您的部署中:

 org.springframework.boot.env.EnvironmentPostProcessor=my.package.name.DBPropertiesLoaderEnvironmentPostProcessor

您可以从此处的文档中阅读更多相关信息: https ://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-boot-application.html#howto-customize-the-environment - 或应用程序上下文

package my.package.name;

import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.sql.DataSource;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.jdbc.datasource.lookup.DataSourceLookupFailureException;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;

import lombok.extern.slf4j.Slf4j;

/**
 * This is used to load property values from the database into the spring application environment
 * so that @Value annotated fields in the various beans can be populated with these database based
 * values.   I can also be used to store spring boot configuration parameters
 *
 * In order for Spring to use this post porcessor this class needs to be added into the META-INF/spring.factories file like so:
 *  org.springframework.boot.env.EnvironmentPostProcessor=my.package.name.DBPropertiesLoaderEnvironmentPostProcessor
 *
 * It will look for the spring boot dataseource properties that traditionally get stored in the application.yml files and use
 * those to create a connection to the database to load the properties.  It first looks for the datasource jndi name property
 * and if that fails it looks for the Spring.datasource.url based properties.
 *
 *
 */
@Slf4j
public class DBPropertiesLoaderEnvironmentPostProcessor implements EnvironmentPostProcessor {

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment env, SpringApplication application) {
        System.out.println("***********************************Pulling properties from the database***********************************");
        if(env.getProperty("spring.datasource.jndi-name") != null) {
            log.info("Extracting properties from the database using spring.datasource.jndi-name");
            try {
                JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
                dsLookup.setResourceRef(true);
                DataSource ds = dsLookup.getDataSource(env.getProperty("spring.datasource.jndi-name"));
                try(Connection con = ds.getConnection()) {
                    env.getPropertySources().addFirst(new DataBasePropertySource(con));
                }
                log.info("Configuration properties were loaded from the database via JNDI Lookup");
            } catch (DataSourceLookupFailureException | SQLException e) {
                log.error("Error creating properties from database with jndi lookup", e);
                e.printStackTrace();
            }
        } else if(env.getProperty("spring.datasource.url") != null){
            String url = env.getProperty("spring.datasource.url");
            String driverClass = env.getProperty("spring.datasource.driver-class-name");
            String username = env.getProperty("spring.datasource.username");
            String password = env.getProperty("spring.datasource.password");
            try {
                DriverManager.registerDriver((Driver) Class.forName(driverClass).newInstance());
                try(Connection c = DriverManager.getConnection(url,username,password);){
                    env.getPropertySources().addFirst(new DataBasePropertySource(c));
                    log.info("Configuration properties were loaded from the database via manual connection creation");
                }
            }catch(Exception e) {
                log.error("Error creating properties from database with manual connection creation.", e);
            }
        } else {
            log.error("Could not load properties from the database because no spring.datasource properties were present");
        }

    }

    /**
     * An implementation of springs PropertySource class that sources from a
     * {@link DataBasedBasedProperties} instance which is java.util.Properties class that
     * pulls its data from the database..
     *
     */
    static class DataBasePropertySource extends EnumerablePropertySource<DataBasedBasedProperties> {

        public DataBasePropertySource(Connection c){
            super("DataBasePropertySource",new DataBasedBasedProperties(c));
        }

        /* (non-Javadoc)
         * @see org.springframework.core.env.PropertySource#getProperty(java.lang.String)
         */
        @Override
        public Object getProperty(String name) {
            return getSource().get(name);
        }

        @Override
        public String[] getPropertyNames() {
            return getSource().getPropertyNames();
        }
    }

    /**
     * Pulls name and value strings from a database table named properties
     *
     */
    static class DataBasedBasedProperties extends Properties {
        private static final long serialVersionUID = 1L;

        private String[] propertyNames;
        public DataBasedBasedProperties(Connection con)
        {
            List<String> names = new ArrayList<String>();
            try(
                    Statement stmt = con.createStatement();
                    ResultSet rs = stmt.executeQuery("select name, value from properties");
            ){
                while(rs.next()) {
                    String name = rs.getString(1);
                    String value = rs.getString(2);
                    names.add(name);
                    setProperty(name, value);
                }
                propertyNames = names.toArray(new String[names.size()]);
            }catch(SQLException e) {
                throw new RuntimeException(e);
            }
        }

        public String[] getPropertyNames() {
            return propertyNames;
        }

    }
}

原文由 David Harris 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题