传送门: SpringBoot+SpringCloud搭建一款企业级开源基础平台
FS平台架构设计说明v1.00
1. 概述
FS平台遵循微服务架构的基本原则,结合产品业务特性,指导和规范各子业务单元进行微服务设计和开发。
1.1. 背景
在传统单体或SOA架构下,应用如果频繁升级更新,开发团队非常痛苦。企业的业务应用经过多年IT建设,系统非常庞大,要改动其中任何一小部分,都需要重新部署整个应用,敏捷开发和快速交付无从谈起。加快互联网+步伐成为许多传统企业的必然选择。业务场景、用户习惯和行为在迅速变化,许多传统行业线上业务出现急速增长。在此时脱颖而出的微服务技术,面对上述困惑几乎浑身优点:独立开发、独立部署、独立发布,去中心化管理,支持高并发高可用,支持丰富技术栈,企业可以根据需要灵活技术选型。
1.2. 术语
1.2.1 康威定律
- 第一定律 组织沟通方式会通过系统设计表达出来。
- 第二定律 时间再多一件事情也不可能做的完美,但总有时间做完一件事情。
- 第三定律 线型系统和线型组织架构间有潜在的异质同态特性。
- 第四定律 大的系统组织总是比小系统更倾向于分解。
2. 架构设计
2.1. 技术架构
3. 微服务设计
3.1 概述
编程是一个还很年轻的行业,计算机从出现到现在也不过 70 年左右,因此我们总是在现存的行业中不断寻找,探索,尝试。从最初的单体架构到之后的分布式架构在到现在的微服务架构说明我们的确也在寻找更好的方法来构建我们的应用,从而提高客户满意度和开发效率。微服务不是被发明出来的,而是随着区域领域设计,持续交付,按需虚拟化,小团队自治协作,大型集群系统的流行等现实中总结出来的一种趋势或模式。
3.2 微服务概念
- 微服务:微服务是一些协同工作的小而自治的服务。 —丛书,微服务设计
3.3 微服务拆分原则
服务拆分是为了横向扩展,应该横向拆分,而非纵向拆成一串连续服务。
- 单一职责原则
把因相同原因而变化的东西聚合在一起,把因不同原因而变化的东西分离出来。这就是我们常说的内聚性。
- 拆分原则(服务边界)
一个微服务应该可以在两周内完全重写,这个经验法则在某些特定的场合下是有效的。 --复杂度拆分
大家通常能够意识到什么是“过大”,如果你不在感觉到你的代码库过大,可能他就是足够小了,足够小即可。–最小原则拆分
最小拆分原则需要注意的一个问题是:服务越小虽然独特性的好处显而易见,但是管理大量服务也会越发的复杂。
如果代码库过大,当下团队无法正常运维,那么应该将其拆分成小的。—组织匹配度拆分
然而一个常见的拆分误区是通过代码库的大小或代码行数来衡量。因为服务代码存在依赖项,每个依赖项又会包含很多代码。
- 基础服务层:
用于屏蔽数据库,缓存层,提供原子的对象查询接口。当数据层发生改变时,例如分库分表,数据库扩容,缓存替换等,不影响上层应用。上层应用仅调用基础服务层接口,不直接访问数据库和缓存。
- 组合服务层:
调用基础服务层,完成复杂的业务逻辑,实现分布式事务。
- 接口层:
接口层,调用组合服务层对外提供服务。
3.4 微服务自治
你是否能够修改一个服务并对其进行部署,而不影响其它任何服务。 —黄金法则
我们尽量避免把多个服务部署到同一台机器上。服务之间通暴露必要的API(Application Programming Interface,应用编程接口)进行网络通信,避免接口之间耦合从而提高服务的自治性。
4. 命名规范
4.1 服务命名
服务命名在同一注册中心需具有唯一性,最长为45个字符,只能包含小写字母、数字及分隔符("_"、"-"),且不能以分隔符开头或结尾。其命名规则如下:微服务名称={fs}-{服务名称}-{service}。
-
{fs}:平台标识。
-
{服务名称}: 服务名,依据服务用途来命名,确保可阅读性和唯一性。
-
{service}:对外提供接口的后台应用命名以“-service”结尾。
基础服务:fs-base-service
4.2 接口命名
为了保证统一资源标识符的“可寻址性”和“可读性”。服务资源标识采用统一资源标识(URI)的语法进行定义,包括:
{域名/ip:port}/{组件名称}/{服务版本}/{接口名称} 。版本号目前不做强制要求。
4.3 接口命名
请求相应遵循Restful风格:
-
统一采用post请求
-
返回结果为统一的Json格式,出于平台标准化的API管理,另一方面,遵循微服务的宽进严出设计理念。返回结果为状态码+Json格式的业务数据。
4.4 包命名
包名全部小写,所有的类文件必须在包 com.fs或子包中,否则项目构建会加载不到类文件。常用包路径:
包名 | 说明 |
---|---|
com.fs | 服务启动类 |
com.fs.xxx.util | 常用工具类 |
com.fs.xxx. enums | 枚举类 |
com.fs.xxx.model | 实体类,和数据库表对应 |
com.fs.xxx.dto | 数据交互传输类,一般用于业务数据封装 |
com.fs.xxx.vo | 数据展示类,一般用于数据展示封装 |
com.fs.xxx.mapper | 数据仓库(数据交互、sql查询) |
com.fs.xxx.service | 业务接口 |
com.fs.xxx.service.impl | 业务接口实现 |
com.fs.xxx.feign | 服务间交互接口调用 |
com.fs.xxx.controller | 对外声明接口 |
com.fs.xxx.config | 配置类 |
4.5. 类命名
类名使用 UpperCamelCase 风格,必须遵从驼峰形式。如果使用到了设计模式,建议在类名中体现出具体模式。
数据仓库类:以Mapper结尾 如SettingProjectMapper
业务接口类:以Service结尾 如SettingProjectService
业务实现类:以ServiceImpl结尾 如SettingProjectServiceImpl
服务接口:以Controller结尾 如 SettingProjectController
4.6. 方法/参数/变量命名
方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从驼峰形式。
正例:getCalendar()、branchType、protectName
常量命名全部大写,单词间用下划线隔开。
正例:CHINA_ID_MAX_LENGTH /** 中国公民身份证号码最大长度。 */
4.7. 变长参数
在Java5 中提供了变长参数(varargs),也就是在方法定义中可以使用个数不确定的参数,对于同一方法可以使用不同个数的参数调用。
4.7.1. 可变长参数的定义
使用…表示可变长参数,例如
print(String... args){
...
}
在具有可变长参数的方法中可以把参数当成数组使用,例如可以循环输出所有的参数值。
print(String... args){
for(String temp:args)
System.out.println(temp);
}
4.7.2. 可变长参数的使用规则
在调用方法的时候,如果能够和固定参数的方法匹配,也能够与可变长参数的方法匹配,则选择固定参数的方法。看下面代码的输出:
package com;
// 这里使用了静态导入
import static java.lang.System.out;
public class VarArgsTest {
public void print(String... args) {
for (int i = 0; i < args.length; i++) {
out.println(args[i]);
}
}
public void print(String test) {
out.println("----------");
}
public static void main(String[] args) {
VarArgsTest test = new VarArgsTest();
test.print("hello");
test.print("hello", "alexia");
}
}
如果要调用的方法可以和两个可变参数匹配,则出现错误,例如下面的代码:
package com;
// 这里使用了静态导入
import static java.lang.System.out;
public class VarArgsTest1 {
public void print(String... args) {
for (int i = 0; i < args.length; i++) {
out.println(args[i]);
}
}
public void print(String test,String...args ){
out.println("----------");
}
public static void main(String[] args) {
VarArgsTest1 test = new VarArgsTest1();
test.print("hello");
test.print("hello", "alexia");
}
}
一个方法只能有一个可变长参数,并且这个可变长参数必须是该方法的最后一个参数,以下两种方法定义都是错误的。
public void test(String... strings,ArrayList list){
}
public void test(String... strings,ArrayList... list){
}
4.7.3. 可变长参数的使用规范
- 避免带有可变长参数的方法重载,编译器虽然知道怎么调用,但人容易陷入调用的陷阱及误区.
- 别让null值和空值威胁到变长方法。
4.7.4. 覆写变长方法要循规蹈矩
这里,总结下覆写必须满足的条件:
(1)重写方法不能缩小访问权限;
(2)参数列表必须与被重写方法相同(包括显示形式);
(3)返回类型必须与被重写方法的相同或是其子类;
(4)重写方法不能抛出新的异常,或者超过了父类范围的异常,但是可以抛出更少、更有限的异常,或者不抛出异常。
最后的最后
为初学者提供学习指南,为从业者提供参考价值。我坚信码农也具有产生洞见的能力。扫描下图二维码关注,学习和交流!