如何从properties文件和数据库读取相关配置

当配置项太多或者有几套配置项的时候,我们不光从properties文件中读取配置项,还要从数据库中读取配置项。从数据库中读取配置项可以通过PropertyPlaceholderConfigurer的子类来实现。

假设数据源配置在conf.properties中,先在该文件中配置properties文件的路径(这里是为了从文件中读取配置项)。
如何从properties文件和数据库读取相关配置

<!-- load conf.properties -->
    <bean id="sysPropertyPlaceHolder" class="com.cloud.extend.spring.ExtendSpringPropertyPlaceholder">
        <property name="locations">
            <list>
                <value>classpath:conf.properties</value>
            </list>
        </property>
    </bean>

配置表如下:

如何从properties文件和数据库读取相关配置

其中ExtendSpringPropertyPlaceholder是继承了PropertyPlaceholderConfigurer的子类,具体实现如下:

package com.cloud.extend.spring;


import com.mysql.jdbc.Connection;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;

import java.io.IOException;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;

/**
 * @Author: Mr.Li
 * @Date: Created on 2019/5/13
 * 当spring加载配置文件时,将配置文件的键值在SystemPropertyCache中初始化
 */
public class ExtendSpringPropertyPlaceholder extends PropertyPlaceholderConfigurer {
    private static final Logger logger = LoggerFactory.getLogger(PropertyPlaceholderConfigurer.class);

    private String driverClass = null;
    private String url = null;
    private String userName = null;
    private String password = null;

    static java.sql.Connection conn = null;

    private String sql =
        "select property_key,property_value from property_config_data where property_type = ? order by property_type";

    /**
     * 重载父类
     */
    @Override protected void processProperties(ConfigurableListableBeanFactory factory, Properties props)
        throws BeansException {
        Properties location_props = null;
        try {
            //获取父类配置文件
            location_props = super.mergeProperties();
        } catch (IOException e) {
            logger.error(" location_props Error ", e);
        }
        if (location_props == null) {
            location_props = new Properties();
        }
        Connection conn = null;
        try {
            driverClass = location_props.getProperty("jdbc.driver");
            url = location_props.getProperty("jdbc.url");
            userName = location_props.getProperty("jdbc.username");
            password = location_props.getProperty("jdbc.password");
            conn = (Connection) getConn(driverClass, url, userName, password);
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setString(1, "1");
            ResultSet rs = ps.executeQuery();
            while (rs.next()) {
                String key = rs.getString("property_key");
                if (key.startsWith(" ") || key.endsWith(" ")) {
                    logger.warn("************************************************ key contain space,key=[{}]", key);
                    key = key.trim();
                }
                if (StringUtils.isBlank(key)) {
                    continue;
                }
                String value = rs.getString("property_value");
                if (null != value) {
                    if (key.startsWith("system.")) {
                        System.setProperty(key.substring(7), value);
                    } else {
                        location_props.put(key, value);
                    }
                }
            }
        } catch (Exception e) {
            logger.error("SQL Erroe", e);
        } finally {
            try {
                if (conn != null) {
                    conn.close();
                }
            } catch (Exception e) {
                logger.error("Close Error", e);
            }
        }
        super.processProperties(factory, location_props);
        for (Object key : location_props.keySet()) {
            String keyStr = key.toString();
            String value = location_props.getProperty(keyStr);
            SystemPropertyCache.put(keyStr, value);
        }
    }

    // 创建连接
    public static java.sql.Connection getConn(
        String driverClass, String url, String userName, String psssword) {
        try {
            Class.forName(driverClass);
            conn = DriverManager.getConnection(url, userName, psssword);
        } catch (Exception e) {
            System.out.println("--找不到驱动程序类 ,加载驱动失败!--");
            e.printStackTrace();
        }
        return conn;
    }
}
可以看到,bean实例化时会调用processProperties方法,从数据库中查询property_type = setting的记录,然后把对应的properties_key和properties_value放入Property类型的内存对象location_props中。然后就可以通过“@{xxxx(这里的xxx是location_props对象的key,也是数据库中properties_key字段)}”来进行注入了。

其他文件省略。