分布式配置中心超轻量的实现方式(带源码)
程序员文章站
2022-07-15 09:48:13
...
随着微服务成为一种潮流,各种配置也变得越来越烦杂。传统的文本文件的配置方式,已经不能满足现有需求。
缺点如下:
- 修改配置需要重新打包,发布
- 对于一些公共配置,每个应用都要修改,不方便统一管理
分布式配置中心就是为了解决这个问题。
1、原理
分布式配置中心,需要达到以下目的
1:方便的修改配置
2:配置修改后可以热更新,或者通过重启达到目的
先看下流程图
配置统一存储在数据库中,称为配置中心。各个微服务重启的时候,从配置中心读取配置,如果读到配置,则将配置写入本地的配置文件中。如果读取失败,则从本地配置文件中读取配置后,写入数据库中。这样可以保证在数据库失效的时候,应用本地保存的是上次启动的最新配置,不影响微服务启动。
2、实现方式源码概览
1、配置中心核心源码
public class PropertiesFactory {
private PropertiesFactory() {
}
public static Properties createProperties(String projectName, String propertiesName) {
if(System.getenv("PN") != null && !"".equals(System.getenv("PN").trim())) {
projectName = System.getenv("PN");
}
return createPropertiesNoEnvPN(projectName, propertiesName);
}
public static Properties createPropertiesNoEnvPN(String projectName, String propertiesName) {
Properties properties = new Properties();
List<Map<String, String>> propertiesList = new ArrayList();
DataSourceModel dataSourceModel = loadConfig("/configcenter_db.properties");
String rootPath = dataSourceModel.getConfigfilepath();
try {
System.out.println("====================================");
System.out.println(projectName);
System.out.println("====================================");
if(System.getenv("CDB") != null && !"".equals(System.getenv("CDB").trim())) {
dataSourceModel.setIp(System.getenv("CDB"));
}
System.out.println("====================================");
System.out.println(dataSourceModel.getIp());
System.out.println("====================================");
propertiesList = loadConfigFromDb(dataSourceModel, projectName, propertiesName);
System.out.println("====================================");
System.out.println(((List)propertiesList).size());
System.out.println("====================================");
} catch (Exception var10) {
var10.printStackTrace();
}
String saveFile;
if(propertiesList != null && ((List)propertiesList).size() >= 1) {
Iterator var11 = ((List)propertiesList).iterator();
while(true) {
while(var11.hasNext()) {
Map<String, String> resultMap = (Map)var11.next();
String key = ((String)resultMap.get("key")).trim();
String value = ((String)resultMap.get("value")).trim();
if("jdbc.maxActive".equals(key) && SystemTools.isWindows()) {
properties.put(key, SystemTools.getDbInitSize());
} else if("jdbc.initialSize".equals(key) && SystemTools.isWindows()) {
properties.put(key, SystemTools.getDbInitSize());
} else if("jdbc.minIdle".equals(key) && SystemTools.isWindows()) {
properties.put(key, SystemTools.getDbInitSize());
} else {
properties.put(key, value);
}
}
saveFile = getSaveFile(rootPath, projectName, propertiesName);
saveConfigToFile(saveFile, properties);
break;
}
} else {
saveFile = getSaveFile(rootPath, projectName, propertiesName);
properties = getConfigFromFile(saveFile);
insertConfigToDb(dataSourceModel, properties, projectName, propertiesName);
}
Map<String, String> map = System.getenv();
if(map != null) {
String jenv = (String)map.get("JENV");
if(jenv == null || "".equals(jenv)) {
jenv = "dev";
}
properties.put("jenv", jenv);
}
return properties;
}
public static Connection getConnection(DataSourceModel dataSourceModel) {
Connection conn = null;
try {
Class.forName("org.postgresql.Driver");
conn = DriverManager.getConnection("jdbc:postgresql://" + dataSourceModel.getIp() + ":" + dataSourceModel.getPort() + "/" + dataSourceModel.getDatabase(), dataSourceModel.getUsername(), dataSourceModel.getPassword());
} catch (ClassNotFoundException var3) {
var3.printStackTrace();
} catch (SQLException var4) {
var4.printStackTrace();
}
return conn;
}
private static List<Map<String, String>> loadConfigFromDb(DataSourceModel dataSourceModel, String projectName, String propertiesName) {
List<Map<String, String>> propertiesList = new ArrayList();
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = getConnection(dataSourceModel);
if(connection != null) {
statement = connection.createStatement();
resultSet = statement.executeQuery("select * from config_center where projectname = '" + projectName + "' and propertiesname = '" + propertiesName + "'");
if(resultSet != null) {
while(resultSet.next()) {
Map<String, String> map = new IdentityHashMap();
map.put("projectname", resultSet.getString("projectname"));
map.put("propertiesname", resultSet.getString("propertiesname"));
map.put("key", resultSet.getString("key").trim());
map.put("value", resultSet.getString("value").trim());
propertiesList.add(map);
}
}
}
} catch (Exception var16) {
var16.printStackTrace();
} finally {
try {
if(resultSet != null) {
resultSet.close();
}
if(statement != null) {
statement.close();
}
if(connection != null) {
connection.close();
}
} catch (SQLException var15) {
var15.printStackTrace();
}
}
return propertiesList;
}
private static void insertConfigToDb(DataSourceModel dataSourceModel, Properties properties, String projectName, String propertiesName) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = getConnection(dataSourceModel);
if(connection != null) {
statement = connection.createStatement();
Set<Object> keys = properties.keySet();
Iterator var8 = keys.iterator();
while(true) {
Object key;
do {
if(!var8.hasNext()) {
return;
}
key = var8.next();
String qrySql = "select * from config_center where projectname = '" + projectName + "' and propertiesname = '" + propertiesName + "' and key='" + key + "'";
resultSet = statement.executeQuery(qrySql);
} while(resultSet != null && resultSet.next());
String insertSql = "insert into config_center values ('" + projectName + "','" + propertiesName + "','" + key + "','" + properties.get(key) + "')";
statement.executeUpdate(insertSql);
}
}
} catch (Exception var20) {
var20.printStackTrace();
} finally {
try {
if(resultSet != null) {
resultSet.close();
}
if(statement != null) {
statement.close();
}
if(connection != null) {
connection.close();
}
} catch (SQLException var19) {
var19.printStackTrace();
}
}
}
private static DataSourceModel loadConfig(String configFile) {
InputStream input = null;
String host = "";
int port = 0;
String database = "";
String username = "";
String password = "";
String configfilepath = "";
try {
input = PropertiesFactory.class.getResourceAsStream(configFile);
Properties properties = new Properties();
properties.load(input);
host = properties.getProperty("host");
port = Integer.valueOf(properties.getProperty("port")).intValue();
database = properties.getProperty("database");
username = properties.getProperty("username");
password = properties.getProperty("password");
configfilepath = properties.getProperty("configfilepath");
} catch (Exception var17) {
var17.printStackTrace();
} finally {
if(input != null) {
try {
input.close();
} catch (IOException var16) {
var16.printStackTrace();
}
}
}
return new DataSourceModel(host, port, database, username, password, configfilepath);
}
private static void saveConfigToFile(String saveFile, Properties properties) {
ArrayList array = getList(properties);
try {
File file = new File(saveFile);
if(!file.exists()) {
if(!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
file.createNewFile();
}
BufferedWriter bw = new BufferedWriter(new FileWriter(saveFile));
Iterator var5 = array.iterator();
while(var5.hasNext()) {
String s = (String)var5.next();
bw.write(s);
bw.newLine();
bw.flush();
}
bw.close();
} catch (IOException var7) {
var7.printStackTrace();
}
}
private static Properties getConfigFromFile(String saveFile) {
Properties properties = new Properties();
try {
BufferedReader br = new BufferedReader(new FileReader(saveFile));
ArrayList<String> array = new ArrayList();
String line = null;
while((line = br.readLine()) != null) {
line = line.trim();
if(!"".equals(line) && !line.startsWith("#")) {
array.add(line);
}
}
br.close();
properties = getProperties(array);
} catch (Exception var5) {
var5.printStackTrace();
}
return properties;
}
private static String getSaveFile(String rootPath, String projectName, String propertiesName) {
String[] projectNameArray = projectName.split("/");
String[] var4 = projectNameArray;
int var5 = projectNameArray.length;
for(int var6 = 0; var6 < var5; ++var6) {
String project = var4[var6];
if(project != null && !"".equals(project)) {
rootPath = rootPath + File.separator + project;
}
}
return rootPath + File.separator + propertiesName + ".properties";
}
private static ArrayList<String> getList(Properties properties) {
ArrayList<String> array = new ArrayList();
Set<Object> keys = properties.keySet();
Iterator var3 = keys.iterator();
while(var3.hasNext()) {
Object key = var3.next();
array.add(key.toString().trim() + "=" + properties.get(key));
}
return array;
}
private static Properties getProperties(ArrayList<String> array) {
Properties properties = new Properties();
Iterator var2 = array.iterator();
while(var2.hasNext()) {
String str = (String)var2.next();
String[] strArray = str.split("=");
if(strArray.length >= 2) {
properties.put(strArray[0].trim(), str.replace(strArray[0] + "=", "").trim());
}
}
return properties;
}
}
2、应用使用方式
Properties properties = PropertiesFactory.createProperties("supp/node1","dbConfig");
supp/node1是应用名
dbConfig是配置名,对应于dbConfigProperties.
3、数据库结构
推荐阅读