2021SC@SDUSC
Config是什么?
微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行,所以一套集中式的、动态的配置管理设施是必不可少的!
上图所示,假如有三个配置文件,然后每一个配置文件都连接了数据库(同一个),这个时候如果我要换一个数据库使用,那么就要将所有配置文件中的配置进行替换,这个时候我们就可以使用 Config Server 来进行统一配置,这样在我们管理的时候也会比较简单!
我们来看AbstractSQLConfig第一部
1.
PATTERN_RANGE = Pattern.compile("^[0-9%,!=\\<\\>/\\.\\+\\-\\*\\^]+$");
// ^[a-zA-Z0-9_*%!=<>(),"]+$ 导致 exists(select*from(Comment)) 通过!
PATTERN_FUNCTION = Pattern.compile("^[A-Za-z0-9%,:_@&~!=\\<\\>\\|\\[\\]\\{\\} /\\.\\+\\-\\*\\^\\?\\$]+$");
//TODO 改成更好的正则,校验前面为单词,中间为操作符,后面为值
凡是 SQL 边界符、分隔符、注释符 都不允许,例如 ' " ` ( ) ; # -- ,以免拼接 SQL 时被注入意外可执行指令
这里用到了 java.util.regex.Pattern
Pattern.compile函数语法
Pattern Pattern.compile(String regex, int flag)
知识学习
Pattern.compile函数中两个参数
1、regex 表示定义的规则
2、flag 表示设置的参数类型,主要包含以下几种情况:
(1)Pattern.CASE_INSENSITIVE(?i) 默认情况下,大小写不明感的匹配只适用于US-ASCII字符集。让表达式忽略大小写进行匹配。
(2)Pattern.COMMENTS(?x) 此种模式下,匹配时会忽略表达式中空格字符(表达式里的空格,tab,回车)。注释从#开始,一直到这行结束。
(3)Pattern.UNIX_LINES(?d) 此种模式下,只有’\n’才被认作一行的中止,并且与’.’,’^’,以及’$’进行匹配。
(4)Pattern.MULTILINE(?m) 此种模式下,上箭头和单引号分别匹配一行的开始和结束。此外,’^‘仍然匹配字符串的开始,’’也匹配字符串的结束。默认情况下,这两个表达式仅仅匹配字符串的开始和结束。
(5)Pattern.DOTALL:此种模式下,表达式’.‘可以匹配任意字符,包括表示一行的结束符。默认情况下,表达式’.'不匹配行的结束符。
实现的功能是对字符串进行截取,排除SQL 边界符、分隔符、注释符的情况
2.
TABLE_KEY_MAP = new HashMap<String, String>();
TABLE_KEY_MAP.put(Table.class.getSimpleName(), Table.TABLE_NAME);
TABLE_KEY_MAP.put(Column.class.getSimpleName(), Column.TABLE_NAME);
TABLE_KEY_MAP.put(PgClass.class.getSimpleName(), PgClass.TABLE_NAME);
TABLE_KEY_MAP.put(PgAttribute.class.getSimpleName(), PgAttribute.TABLE_NAME);
TABLE_KEY_MAP.put(SysTable.class.getSimpleName(), SysTable.TABLE_NAME);
TABLE_KEY_MAP.put(SysColumn.class.getSimpleName(), SysColumn.TABLE_NAME);
TABLE_KEY_MAP.put(ExtendedProperty.class.getSimpleName(), ExtendedProperty.TABLE_NAME);
此处用到了java.util.HashMap;
知识学习
HashMap是我们最常用的类之一,它实现了hash算法
HashMap存储的是key-value形式的键值对,这个键值对在实现中使用一个静态内部类Entry来表示,它存储了key、value、hash值、以及在hash冲突时链表中下一个元素的引用。
HashMap底层实现使用了一个数组来存储元素。它的初始容量默认是16,而且必须容量必须是2的整数次幂,最大容量是1<<30(10.7亿+),同时还使用一个加载因子(load factor)来控制这个map的这个hash表的扩容,默认为0.75,即当容量达到初始容量3/4时会扩容(当然不只这样,后面会说明)。
在往HashMap中添加元素时,会计算key的hashCode,然后基于这个hashCode和数组大小来确定它在数组中的存储位置,当遇到hash冲突时,会以链表的形式存储在数组中。
简介put(key, value)方法的执行过程:
通过key值,使用散列算法计算出来一个hash值,用来确定该元素需要存储到数组中的哪个位置(index)。
根据计算出来的位置(index),可以查看该位置是否被占用:
如果位置(index)未被占用,将(key\value)封装成一个节点,保存到该位置。
如果位置(index)被占用,使用key和链表中的节点一一比较:
---->如果链表中不存在该key,将(key/value)封装成节点添加到该链表中。
---->如果链表中已存在该key,替换该key对应节点的value值。
上图代码中使用的put方法将键值对加入到Map中,
如果key在Map中已经存在,则会被替换并且返回这个旧值,不存在则返回null
V put(K key, V value);
在本项目代码中使用的意义在于将方法名和值对应起来
如Table.class.getSimpleName()=Table.TABLE_NAME
3.
CONFIG_TABLE_LIST = new ArrayList<>(); // Table, Column 等是系统表 AbstractVerifier.SYSTEM_ACCESS_MAP.keySet());
CONFIG_TABLE_LIST.add(Function.class.getSimpleName());
CONFIG_TABLE_LIST.add(Request.class.getSimpleName());
CONFIG_TABLE_LIST.add(Response.class.getSimpleName());
CONFIG_TABLE_LIST.add(Access.class.getSimpleName());
CONFIG_TABLE_LIST.add(Document.class.getSimpleName());
CONFIG_TABLE_LIST.add(TestRecord.class.getSimpleName());
DATABASE_LIST = new ArrayList<>();
DATABASE_LIST.add(DATABASE_MYSQL);
DATABASE_LIST.add(DATABASE_POSTGRESQL);
DATABASE_LIST.add(DATABASE_SQLSERVER);
DATABASE_LIST.add(DATABASE_ORACLE);
DATABASE_LIST.add(DATABASE_DB2);
DATABASE_LIST.add(DATABASE_CLICKHOUSE);
这里用到了java.util.ArrayList;
知识学习
数组和数组列表之间有着重大的区别。数组是 Java 语言的一个特征,对于每个元素类型 T ,都有数组类型 T[]; 然而, ArrayList 类是个定义 java.util 包中的类库。这是一个存放 object 类型元素的 " 普通性 " 的类型。要注意的是,要从数组列表中提取元素时,需要进行类型转换。
使用 add 方法可以向数组列表中添加新元素:
ArrayList staff = new ArrayList();
staff.add(new Employee(....));
staff.add(new Employee(....));
在该段代码中,是向CONFIG_TABLE_LIST和DATABASE_LIST中添加数据
这里需要一提的是
public abstract class AbstractSQLConfig implements SQLConfig
该类实现SQLConfig接口
这里放上SQLConfig的代码