公司的工程基於dubbo,不少工程,配置寫在文件中是一個很麻煩的問題。配置管理成爲急需解決的問題。java
採用配置中心,配置寫在數據庫,便於集中管理。各工程在文件中的配置固定不變。mysql
一、公共模塊config-common,一個普通的jar工程redis
<groupId>com.wss.lsl</groupId> <artifactId>config-common</artifactId> <version>0.0.1-SNAPSHOT</version>
數據庫配置spring
create database config_center; use config_center; -- 配置表 CREATE TABLE app_config( CONFIG_ID VARCHAR(40) COLLATE utf8_unicode_ci NOT NULL COMMENT '主鍵', ENV_NAME VARCHAR(40) COLLATE utf8_unicode_ci NOT NULL COMMENT '環境名:dev/test/product等', PROJECT_NAME VARCHAR(100) COLLATE utf8_unicode_ci NOT NULL COMMENT '工程名', CONFIG_NAME VARCHAR(100) COLLATE utf8_unicode_ci NOT NULL COMMENT '配置名', CONFIG_VALUE VARCHAR(500) COLLATE utf8_unicode_ci NOT NULL COMMENT '配置值', CONFIG_SORT INT(11) DEFAULT 1 COMMENT '配置排序:屬性能夠引用前面的屬性', CONFIG_DESC VARCHAR(200) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '配置描述', CREATE_TIME datetime NOT NULL COMMENT '建立時間', UPDATE_TIME datetime NOT NULL COMMENT '更新時間', CREATE_USER VARCHAR(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '建立人', UPDATE_USER VARCHAR(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '修改人', IS_VALID INT(11) DEFAULT '1' COMMENT '是否有效:1有效、0無效', PRIMARY KEY (`CONFIG_ID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='配置表'; INSERT INTO app_config(CONFIG_ID, ENV_NAME, PROJECT_NAME, CONFIG_NAME, CONFIG_VALUE, CONFIG_DESC, CREATE_TIME, UPDATE_TIME, CREATE_USER, UPDATE_USER, IS_VALID) VALUES ('752af6b371ee11e7a1bf080058000001', 'dev', 'boot-server', 'server.port', '8080', 'http監聽端口', now(), now(), 'wei.ss', 'wei.ss', 1), ('786ccb9771ee11e7a1bf080058000001', 'dev', 'common', 'server.session.timeout', '1800', '會話超時時間', now(), now(), 'wei.ss', 'wei.ss', 1);
maven依賴,爲了減小依賴,採用jdbc從數據庫加載配置。sql
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies>
CommonConfig代碼數據庫
import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.EnvironmentAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.core.env.Environment; /** * 公共配置 * * <pre> * 屬性配置的優先級<br> FIXME * 優先級:操做系統環境變量 > application.properties > this project > common project * </pre> * * @author wei.ss * @date 2017年7月26日 */ @Configuration public class CommonConfig implements EnvironmentAware { private final Logger LOG = LoggerFactory.getLogger(getClass()); // @Autowired注入不進來,要實現接口EnvironmentAware才能夠。 Environment env; @Override public void setEnvironment(Environment environment) { this.env = environment; } @Bean(name = "configProperties") public FactoryBean<Properties> configProperties() { String jdbcUrl = env.getProperty("config.center.jdbc.url"); String jdbcUser = env.getProperty("config.center.jdbc.user"); String jdbcPassword = env.getProperty("config.center.jdbc.password"); String envName = env.getProperty("config.center.env.name"); String projectName = env.getProperty("config.center.porject.name"); LOG.info( "工程的配置中心信息:jdbcUrl={},jdbcUser={},jdbcPassword={},envName={},projectName={}", jdbcUrl, jdbcUser, jdbcPassword, envName, projectName); return new PropertiesFactoryBean(jdbcUrl, jdbcUser, jdbcPassword, envName, projectName); } @Bean public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer( @Autowired @Qualifier("configProperties") FactoryBean<Properties> configProperties) throws Exception { PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer(); configurer.setProperties(configProperties.getObject()); configurer.setLocalOverride(false); // 確保從properties文件讀取的配置優先級大於configProperties configurer.setTrimValues(true); // 去掉配置值先後的空格 return configurer; } }
PropertiesFactoryBean代碼緩存
import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.FactoryBean; /** * 配置工廠bean * * @author wei.ss * @date 2017年7月26日 */ public class PropertiesFactoryBean implements FactoryBean<Properties> { private static final Logger LOG = LoggerFactory .getLogger(PropertiesFactoryBean.class); // 全部工程的公共配置 private static final String COMMON_PROJECT = "common"; // 查詢配置的sql private static final String SQL = "SELECT CONFIG_NAME, CONFIG_VALUE, CONFIG_SORT FROM app_config " + "WHERE ENV_NAME='%1$s' AND PROJECT_NAME='%2$s' AND IS_VALID=1 ORDER BY CONFIG_SORT ASC"; private String jdbcUrl; private String jdbcUser; private String jdbcPassword; private String envName; private String projectName; private Properties properties; public PropertiesFactoryBean(String jdbcUrl, String jdbcUser, String jdbcPassword, String envName, String projectName) { super(); this.jdbcUrl = jdbcUrl; this.jdbcUser = jdbcUser; this.jdbcPassword = jdbcPassword; this.envName = envName; this.projectName = projectName; // 初始化工程配置 init(); } // 初始化工程配置 private void init() { LOG.info("開始初始化工程配置:envName={},projectName={}", envName, projectName); Connection connection = null; try { Class.forName("com.mysql.jdbc.Driver").newInstance(); connection = DriverManager.getConnection(jdbcUrl, jdbcUser, jdbcPassword); fillProperties(connection, COMMON_PROJECT); fillProperties(connection, projectName); } catch (Exception e) { LOG.error("初始化工程配置發生異常", e); LOG.error( "初始化工程發生異常參數:jdbcUrl={},jdbcUser={},jdbcPassword={},envName={}, projectName={}", jdbcUrl, jdbcUser, jdbcPassword, envName, projectName); throw new RuntimeException(e); } finally { LOG.info("初始化工程配置完成:properties={}", properties); if (null != connection) { try { connection.close(); } catch (SQLException e) { LOG.error("關閉數據庫鏈接發生異常", e); } } } } // 填充屬性配置 private void fillProperties(Connection connection, String projectName) { String sql = String.format(SQL, envName, projectName); Statement statement = null; ResultSet rs = null; try { statement = connection.createStatement(); rs = statement.executeQuery(sql); String configName = null; String configValue = null; while (rs.next()) { if (properties == null) { properties = new Properties(); } configName = rs.getString(1); configValue = rs.getString(2); properties.put(configName, configValue); } } catch (SQLException e) { LOG.error("查詢工程配置發生異常", e); } finally { if (rs != null) { try { rs.close(); } catch (SQLException e) { // ignore } } if (statement != null) { try { statement.close(); } catch (SQLException e) { // ignore } } } } @Override public Properties getObject() throws Exception { return properties; } @Override public Class<?> getObjectType() { return Properties.class; } @Override public boolean isSingleton() { return true; } }
二、其餘工程引用配置session
引用config-commonapp
<dependency> <groupId>com.wss.lsl</groupId> <artifactId>config-common</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
加載配置maven
CommonConfig就是上面公共模塊中的代碼
@SpringBootApplication @Import({CommonConfig.class}) @PropertySource(value = { "file:/etc/pay_background/spring-boot/application.properties" }) public class BootApplication { // ... }
application.properties的內容以下:不一樣環境只要修改config.center.jdbc.url和config.center.env.name,後期新增修改配置,只要往數據庫添加或修改記錄便可。
# 配置中心配置 config.center.jdbc.url=jdbc:mysql://192.168.1.104:3306/test?characterEncoding=utf-8 config.center.jdbc.user=root config.center.jdbc.password=123456 config.center.env.name=dev config.center.porject.name=boot-server
三、擴展優化。把配置寫入數據庫,新增一個工程config-server,專門從數據庫加載配置寫入緩存(如redis),其餘工程從緩存讀取配置,這樣工程啓動速度快,數據庫的壓力也小。