微服务架构设计实践
 


目    次

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;


  微信扫一扫,关注该公众号

  该系列文章已经在微信公众号发布,如果感兴趣,请关注。

   以后更多知识通过该微信公众号分享。


Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐