4.4.6 开发架构
4.4.6.1 开发架构定义
开发架构定义了软件开发环境中,软件模块的实际组织方式,具体涉及源程序文件、配置文件、源程序包、编译后的目标文件、第三方库文件等。
开发架构的设计着重考虑开发期质量属性,如可扩展性、可重用性、可移植性、易理解性和易测试性等。
为了避免开发人员不按照架构进行详细设计和编程,应该重视“开发架构视图”,让开发人员看到他们最关心的“程序单元“、”源代码目录结构“等内容,这些是不同程序团队开展具体工作的基础。如果程序员们不能从架构中看到上述内容,就会认为架构是一类“高来高去“的概念,就不会有积极态度。
从系统开发人员的角度来考虑问题,设计的架构要易于理解,易于开发,易于单元测试,最好做到让开发人员可以用最少的代码行数完成功能的开发。
开发架构设计要达到能支持并行的详细设计。
开发架构的设计主要完成下列工作:
1.程序单元划分
源文件、配置文件;
程序库、框架;
目标单元;
2.程序单元组织
项目划分;
项目目录结构;
编译依赖关系;
4.4.6.2 开发架构设计原则
4.4.6.2.1 模块内设计原则对于模块内的代码设计,遵循SOLID原则:
1.S:单一责任原则,如果你的代码中有一个类行数太长,可能你需要重新审视一下,是不是这个类承担了过多的责任。
2.O:开放关闭原则,对扩展开放,对修改关闭。由于对于代码的直接修改是非常危险的事情,因为你不知道这段代码原来被谁用了,因此不要贸然修改一段代码,而是选择用接口进行调用,用实现进行扩展的方式进行。
3.L:里氏替换原则,如果基于接口进行编程,则子类一定要能够扩展父类的功能,如果不能,说明不应该继承与这个接口。例如你的实现的时候,发现接口中有一个方法在你这里实在对应不到实现,不是接口设计的问题,就是你不应该继承这个接口,绝不能出现not implemented类似之类的实现方法。
4.I:接口隔离原则,接口不应该设计的大而全,一个接口暴露出所有的功能,从而使得客户端依赖了自己不需要的接口或者接口的方法。而是应该讲接口进行细分和提取,而不应该将太过灵活的参数和变量混杂在一个接口中。
5.D:依赖倒置原则,A模块依赖于B模块,B模块有了修改,反而要改A,就是依赖的过于紧密的问题。这就是常说的,你变了,我没变,为啥我要改。如果基于抽象的接口编程,将修改隐藏在后面,则能够实现依赖的解耦。
4.4.6.2.2 模块间设计原则
对于模块之间,则是采用云应用常说的十二原则,也称为云应用迁移原则。如果应用满足这12个要素,则可以比较顺利迁移到各种云平台。
1.基准代码
一份基准代码,多份部署。如果用镜像部署方式,则一个镜像可以部署到多个环境 (测试,预发,生产),而不是给每个环境制作一个不同镜像。
2.依赖
显式声明依赖。如果用镜像部署,则一般依赖被直接打在镜像中,或者声明在dockerfile中。
3.配置
在环境中存储配置。
4.后端服务
把后端服务 (例如缓存,数据库,MQ 等) 当作附加资源,相关配置和连接字符串通过环境变量注入,或者采用配置中心。
5.构建、发布和运行
严格分离构建和运行。如果使用镜像部署,则构建、发布、运行是通过镜像这种中间格式严格分离的。
6.进程
一个或者多个无状态的进程运行应用。容器运行时相当于进程,适用于无状态 Web/API。
7.端口绑定
通过端口绑定提供服务。容器也是通过端口绑定对外提供服务。
8.并发
通过进程模型进行扩展。容器运行时相当于进程,通过起多个容器可以任意扩展并发数量。
9.易处理
快速启动和优雅终止可最大化健壮性。docker 容器支持秒级启动和关闭。
10.开发环境和线上环境等价
尽可能保持开发、测试、预发和线上环境相同。容器可以保证容器内运行时环境的一致性,还需要保证不同环境的一致性,例如不同环境内的操作系统,负载均衡,服务发现,后台服务,监控告警等要尽可能一致。
11.日志
把日志当作数据流。
12.管理进程
后台管理任务当作一次性的进程。
4.4.6.3 开发架构实践-通用组件应用
4.4.6.3.1 代码组织结构
1.后台应用
按照模块分层进行组织,具体分为:
公共服务模块:bcap-common-base
总分通讯模块:bcap-common-client
日终模块:bcap-common-dayend
风控模块:bcap-common-riskcontrol
自动任务调度模块:bcap-common-scheduler
其它公共模块:bcap-common-模块名称
系统管理模块:bcap-common-rbac;(开发环境使用,生产环境采用Tesla统一应用监控配置中心进行部署)
2.前台控制台
单独一个Web应用,调用后台应用提供的各种服务完成相关功能;
4.4.6.3.2 模块依赖关系
1.bcap-common-base
该模块为全局公共模块,其它各模块以项目依赖的方式直接引用,在类中直接import该模块下的类。
模块依赖设置:(模块下pom.xml)
<dependency>
<groupId>com.cmbc.bcap</groupId>
<artifactId>bcap-common-base</artifactId>
<version> ${bcap-common-version}</version>
</dependency>
2.其它公共模块以Jar包方式、服务方式提供服务。
4.4.6.3.3 目录结构项目整体结构采用Maven的多级模块结构,本项目采用2级结构,即便于模块的分类管理,同时避免级数太多带来的代码管理方面的问题。
1.一级目录:
bcap-common-parent
2.二级目录:
后台应用模块:bcap-common-app
公共服务模块:bcap-common-base
分行服务调用客户端模块:scc-common-client
日终模块:bcap-common-dayend
风控模块:bcap-common-riskcontrol
自动任务调度模块:bcap-common-scheduler
其它公共模块:bcap-common-模块名称
前台应用模块:bcap-common-web
4.4.6.3.3.1 公共服务模块目录:(以base模块为例)1.项目结构采用Maven默认推荐结构:
src/main/java存放应用Java代码;
src/main/resources存放应用配置文件;
src/test/java存放应用测试代码;
src/test/resources存放应用测试配置;
2.Java代码目录层次:
此模块为全局共用模块,主要存放全局的常量定义、工具类、全局过滤器等。
常量类(constant):存放本模块使用的常量定义;
工具类(util):存放本模块使用的工具类;
过滤器(filter):存放本模块使用的过滤器类;
其它:如果有特殊需要,可根据实际情况创建相关目录;
3.日志配置文件:
统一存放在src/main/resources文件夹下,名称为logback.xml。
此为全局性的日志配置文件,在模块中不再单独需要日志配置文件。
4.log4j或logback日志文件:
建议预留一个磁盘空间比较大(至少50G)的磁盘专门用于存放日志文件。
5.模块配置文件:
统一存放在src/main/resources/META-INF/common文件夹下。
配置文件包括,但不限于下述文件:
datasource.xml
security-realm.xml
4.4.6.3.3.2 其它公共模块目录:(以dayend模块为例)
1.项目结构采用Maven默认推荐结构:
src/main/java存放应用Java代码;
src/main/resources存放应用配置文件;
src/test/java存放应用测试代码;
src/test/resources存放应用测试配置;
2.Java代码目录层次:
针对每个模块,采用Tesla通用的三层结构,具体划分为:
1) 业务层(function):
业务处理,在此层进行数据库事务控制;
一个function对应一个业务功能,避免在一个function中定义多个业务功能;
对于业务功能较多(大于等于20个业务功能)的模块,建议建立子目录,对function进行分类管理;
对于同一个模块中功能可以进行分组管理;
2) 服务层(manager):
数据库组合操作,以便功能复用;
对于function需要调用的mapper中的原子操作,也必须在manager层进行封装,即直接透传,不能在function中直接调用mapper中的功能;
3) 数据访问层(mapper):
数据库原子操作,例如:单表的增删改查、多表的关联查询等;
其它目录:
实体域(domain):数据库表对应的Java Bean;
常量类(constant):存放本模块使用的常量定义;
工具类(util):存放本模块使用的工具类;
过滤器(filter):存放本模块使用的过滤器类;
其它:如果有特殊需要,可根据实际情况创建相关目录;
3.MessageSource配置文件:
统一存放在src/main/resources/META-INF/模块名/messages文件夹下。
例如:src/main/resources/META-INF/dayend/messages;
4.MyBatis配置文件:
统一存放在src/main/resources/META-INF/模块名/services/mapper文件夹下。
例如:src/main/resources/META-INF/dayend/services/mapper;
5.模块配置文件:
统一存放在src/main/resources/META-INF/模块名/services文件夹下。
例如:src/main/resources/META-INF/dayend/services;
基础配置文件包括,但不限于下述文件:
mybatis-config.xml
security.xml
cache-config.xml
6.初始化数据
统一存放在src/main/resources/initdata文件夹下。
4.4.6.4 开发架构实践-总行服务融合中心
4.4.6.4.1 代码组织结构
1. 后台应用
按照模块分层进行组织,具体分为:
1) 公共服务:bcap-scc-common
全局公共基础模块:bcap-scc-common-base
其它公共服务模块:bcap-scc-common-模块名称
2) 原子服务:bcap-scc-baseservice
产品模块:bcap-scc-baseservice-product
订单模块:bcap-scc-baseservice-order
其它原子服务模块:bcap-scc-baseservice-模块名称
3) 流程服务:bcap-scc-flowservice
支付模块:bcap-scc-flowservice-payment
信贷模块:bcap-scc-flowservice-credit
其它流程服务模块:bcap-scc-flowservice-模块名称
4) 系统管理模块:bcap-scc-rbac;(开发环境使用,生产环境采用Tesla统一应用监控配置中心进行部署)
2.前台控制台单
独一个Web应用,调用后台应用提供的各种服务完成相关功能。
4.4.6.4.2 模块依赖关系
1.公共服务模块:
1) bcap-scc-common-base
该模块为总行服务融合中心公共模块,其它各模块以项目依赖的方式直接引用,在类中直接import该模块下的类。
模块依赖设置:(模块下pom.xml)<dependency>
<groupId>${parent.groupId}</groupId>
<artifactId>${common-project-artifactId}</artifactId>
<version>${parent.version}</version>
</dependency>
2)其它公共服务模块
公共服务模块不依赖原子服务、流程服务;
2.原子服务模块
支持模块热部署方式;
原子服务模块不依赖任何其他模块,除bcap-scc-common-base外;
各原子服务模块不对外提供服务;
各原子服务模块之间不能互相调用;
每个原子服务要独立完成一个完整的功能;
3.流程服务模块
支持模块热部署方式;
流程服务模块依赖原子服务模块;
各流程服务模块通过Dubbo对外提供HTTP服务,采用JSON数据格式;
各流程服务模块通过Tesla平台提供的function-invoke调用原子服务模块提供的原子服务;
各流程服务模块之间不能互相调用;
4.4.6.4.3 目录结构
项目整体结构采用Maven的多级模块结构,本项目采用3级结构,即便于模块的分类管理,同时避免级数太多带来的代码管理方面的问题;
1.一级目录:
bcap-scc-parent
2.二级目录:
后台应用模块:bcap-scc-app
公共服务模块:bcap-scc-common
原子服务模块:bcap-scc-baseservice
流程服务模块:bcap-scc-flowservice
前台应用模块:bcap-scc-web
3.三级目录:
1) 公共服务目录bcap-scc-common:
公共模块:bcap-scc-common-base
其它公共服务模块:bcap-scc-common-模块名称
2) 原子服务:bcap-scc-baseservice
产品模块:bcap-scc-baseservice-product
订单模块:bcap-scc-baseservice-order
其它原子服务模块:bcap-scc-baseservice-模块名称
3) 流程服务:bcap-scc-flowservice
支付模块:bcap-scc-flowservice-payment
信贷模块:bcap-scc-flowservice-credit
其它流程服务模块:bcap-scc-flowservice-模块名称
4.4.6.4.3.1 公共服务模块目录:(以base模块为例)1.项目结构采用Maven默认推荐结构:
src/main/java存放应用Java代码;
src/main/resources存放应用配置文件;
src/test/java存放应用测试代码;
src/test/resources存放应用测试配置;
2.Java代码目录层次:
此模块为全局共用模块,主要存放全局的常量定义、工具类、全局过滤器等。
常量类(constant):存放本模块使用的常量定义;
工具类(util):存放本模块使用的工具类;
过滤器(filter):存放本模块使用的过滤器类;
其它:如果有特殊需要,可根据实际情况创建相关目录;
3.日志配置文件:
统一存放在src/main/resources文件夹下,名称为logback.xml。
此为全局性的日志配置文件,在模块中不再单独需要日志配置文件。
4.log4j或logback日志文件:
建议预留一个磁盘空间比较大(至少50G)的磁盘专门用于存放日志文件。
5.模块配置文件:
统一存放在src/main/resources/META-INF/common文件夹下。
配置文件包括,但不限于下述文件:
datasource.xml
security-realm.xml
4.4.6.4.3.2 原子服务模块目录:(以pe模块为例)1.项目结构采用Maven默认推荐结构:
src/main/java存放应用Java代码;
src/main/resources存放应用配置文件;
src/test/java存放应用测试代码;
src/test/resources存放应用测试配置;
2.Java代码目录层次:
针对每个模块,采用Tesla通用的三层结构,具体划分为:
1) 业务层(function):
业务处理,在此层进行数据库事务控制;
一个function对应一个业务功能,避免在一个function中定义多个业务功能;
对于业务功能较多(大于等于20个业务功能)的模块,建议建立子目录,对function进行分类管理;
对于同一个模块中功能可以进行分组管理;
2) 服务层(manager):
数据库组合操作,以便功能复用;
对于function需要调用的mapper中的原子操作,也必须在manager层进行封装,即直接透传,不能在function中直接调用mapper中的功能;
3) 数据访问层(mapper):
数据库原子操作,例如:单表的增删改查、多表的关联查询等;
其它目录:
实体域(domain):数据库表对应的Java Bean;
常量类(constant):存放本模块使用的常量定义;
工具类(util):存放本模块使用的工具类;
过滤器(filter):存放本模块使用的过滤器类;
其它:如果有特殊需要,可根据实际情况创建相关目录;
3.MessageSource配置文件:
统一存放在src/main/resources/META-INF/模块名/messages文件夹下。
例如:src/main/resources/META-INF/pe/messages;
4.MyBatis配置文件:
统一存放在src/main/resources/META-INF/模块名/services/mapper文件夹下。
例如:src/main/resources/META-INF/pe/services/mapper;
5.模块配置文件:
统一存放在src/main/resources/META-INF/模块名/services文件夹下。
例如:src/main/resources/META-INF/pe/services;
基础配置文件包括,但不限于下述文件:
mybatis-config.xml
security.xml
cache-config.xml
6.初始化数据
统一存放在src/main/resources/initdata文件夹下。
4.4.6.4.3.3 流程服务模块目录:(以payment模块为例)
1. 项目结构采用Maven默认推荐结构:
src/main/java存放应用Java代码;
src/main/resources存放应用配置文件;
src/test/java存放应用测试代码;
src/test/resources存放应用测试配置;
2.Java代码目录层次:
由于流程服务模块主要是根据需求对原子服务进行流程编排,所以在本模块只有function层,在function中进行服务流程的调用。1) 业务层(function):
业务流程调用;
一个function对应一个服务流程,避免在一个function中定义多个服务流程;
对于服务流程较多(大于等于20个服务流程)的模块,建议建立子目录,对function进行分类管理;
对于同一个模块中服务流程可以进行分组管理;
其它目录:
工具类(util):存放本模块使用的工具类;
其它:如果有特殊需要,可根据实际情况创建相关目录;
3.MessageSource配置文件:
统一存放在src/main/resources/META-INF/模块名/messages文件夹下。
例如:src/main/resources/META-INF/payment/messages;
4.模块配置文件:
统一存放在src/main/resources/META-INF/模块名/services文件夹下。
例如:src/main/resources/META-INF/payment/services;
基础配置文件包括,但不限于下述文件:
channel-config.xml
dubbo-config.xml
security.xml
security-client.xml
serviceflow-config.xml
5.服务编排流程文件
统一存放在src/main/resources/sflowDiagram文件夹下。
如果服务编排流程文件大于等于20个,可以参考function分类规则,在sflowDiagram目录下按照类别创建子目录进行分类管理。
6.初始化数据
统一存放在src/main/resources/initdata文件夹下。
4.4.6.5 开发架构实践-分行特色应用
以北京分行为例(bcap-bj)。
4.4.6.5.1 代码组织结构
1. 后台应用
按照模块分层进行组织,具体分为:
公共服务模块:bcap-bj-base
贷款模块:bcap-bj-loan
其它模块:bcap-bj-模块名称
系统管理模块:bcap-bj-rbac;(开发环境使用,生产环境采用Tesla统一应用监控配置中心进行部署)
2. 前台控制台
单独一个Web应用,调用后台应用提供的各种服务完成相关功能。
4.4.6.5.2 模块依赖关系
1.bcap-bj-base
该模块为公共模块,其它各模块以项目依赖的方式直接引用,在类中直接import该模块下的类。
模块依赖设置:(模块下pom.xml)<dependency>
<groupId>${parent.groupId}</groupId>
<artifactId>${common-project-artifactId}</artifactId>
<version>${parent.version}</version>
</dependency>
4.4.6.5.3 目录结构
项目整体结构采用Maven的多级模块结构,本项目采用2级结构,即便于模块的分类管理,同时避免级数太多带来的代码管理方面的问题。
1. 一级目录:
bcap-bj-parent
2. 二级目录:
后台应用模块:bcap-bj-app
公共服务模块:bcap-bj-base
贷款模块:bcap-bj-loan
其它模块:bcap-bj-模块名称
前台应用模块:bcap-bj-web
4.4.6.5.3.1 公共服务模块目录:
参考《公共服务模块目录:(以base模块为例)》;
4.4.6.5.3.2 其它模块目录:
参考《原子服务模块目录:(以pe模块为例)》;
4.4.6.6 命名规则
1.项目名称:
1) 对前后台分开场景:以bcap-scc项目名称为例。
前台应用:bcap-scc-web;
后台应用:bcap-scc-app;
2)公共服务模块:
统一异常处理模块:bcap-scc-common-base;
其它公共服务模块:bcap-scc-common-模块名
3) 原子服务模块:
订单模块:bcap-scc-baseservice-order;
其它原子服务模块:bcap-scc-baseservice-模块名称
4) 流程服务模块:
支付模块:bcap-scc-flowservice-payment;
其它流程服务模块:bcap-scc-flowservice-模块名称
2.公共服务模块包名:(以base为例)
Function:com.cmbc.bcap.scc.common.base.function
Manager:com.cmbc.bcap.scc.common.base.manager
Mapper:com.cmbc.bcap.scc.common.base.mapper
domain:com.cmbc.bcap.scc.common.base.domain
util:com.cmbc.bcap.scc.common.base.util
constant:com.cmbc.bcap.scc.common.base.constant
filter:com.cmbc.bcap.scc.common.base.filter
3.原子服务模块包名:(以订单模块order为例)
Function:com.cmbc.bcap.scc.baseservice.order.function
Manager:com.cmbc.bcap.scc.baseservice.order.manager
Mapper:com.cmbc.bcap.scc.baseservice.order.mapper
domain:com.cmbc.bcap.scc.baseservice.order.domain
util:com.cmbc.bcap.scc.baseservice.order.util
constant:com.cmbc.bcap.scc.baseservice.order.constant
filter:com.cmbc.bcap.scc.baseservice.order.filter
4.流程服务模块包名:(以支付模块payment为例)
Function:com.cmbc.bcap.scc.flowservice.payment.function
util:com.cmbc.bcap.scc.flowservice.payment.util
5.Function实现类名称:
业务功能名称+Function.java
如业务功能为订单查询,则对应的function名称为OrderQueryFunction;
注意:Function必须采用注解方式开发;
6.Manager类名称:
服务名称+Manager.java
如服务为客户账单服务,则对应的manager名称为ClientAccountManager.java;
7.Domain类名称:
实体名.java
如实体名为user,则对应的实体域名称为User.java;
8.Util类名称:
功能描述+Util.java
如日期格式转换工具类,则对应的工具类名称为DateFormatUtil.java;
9.常量类名称
常量类别+Constant.java
如错误码类型常量,则对应的常量类名称为ErrorCodeConstant.java;
10.MyBatis中Mapper名称:
1) Mapper接口类名称:
实体名+Mapper.java;
例如:UserMapper.java;
2) Mapper接口类的方法名称:
select、insert、update、delete方法分组定义,按顺序定义不能混乱;
方法名要能明确看出DB操作的含义,统一按照select+xxx+By+yyy或select+xxx+List+By+yyy或select+xxx+withRS、insert+xxx、update+xxx、delete+xxx+By+yyy。(xxx为实体名,yyy为条件描述,多重条件用简称描述);
接口类中方法要有功能说明,描述DB操作的功能;
3) Mapper配置文件名:
实体名+Mapper.xml,和接口类名称对应;
例如:UserMapper.xml;
4) Mapper配置XML文件中配置项名:
同接口定义,select、insert、update、delete分组并按顺序定义,且按照接口方法的顺序在XML中定义;
<select></select>、<insert></insert>、<update></update>、<delete></delete>的id名称与接口中方法名相同;
<sql></sql>共享列定义id名称遵循:定义列为表的部分字段时为simple+xxx+Columns、定义列为表的所有字段时为full+xxx+Columns、定义列为表与其他表关联时为xxx+join+yyy+Columns。(xxx为主实体名、yyy为关联实体名)
<resultMap></resultMap>返回结果映射定义id名称遵循:返回结果为表的部分字段时为simple+xxx+ResultMap、返回结果为表的所有字段时为full+xxx+ResultMap、返回结果为表与其他表关联时为xxx+join+yyy+ResultMap。(xxx为主实体名、yyy为关联实体名)
<sql></sql>和<resultMap></resultMap>定义在XML的最前面,后面再开始定义<select></select>、<insert></insert>、<update></update>、<delete></delete>;
5) MessageSource配置文件名:
实体名-message-source-zh_CN.properties
6) MessageSource文件中配置项Key名称:
function名称.消息码,统一小写;
例如:queryUserDetail.userid_not_exist;
微信扫一扫,关注该公众号
该系列文章已经在微信公众号发布,如果感兴趣,请关注。
以后更多知识通过该微信公众号分享。