基于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),其余工程从缓存读取配置,这样工程启动速度快,数据库的压力也小。

相关文章
相关标签/搜索