基於spring-boot的配置中心

公司的工程基於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),其餘工程從緩存讀取配置,這樣工程啓動速度快,數據庫的壓力也小。

相關文章
相關標籤/搜索