账户中心框架介绍

# 账户中心框架介绍

### 改造目的:

* 降低代码耦合度

* 增加代码复用性,提高开发效率

* 重新规划定义模块及职责,以更快速地响应需求变更

* 优化调整部分业务实现,提高系统的稳定性与扩展性

## 技术架构调整

### 技术选型

* 公共

* 编译插件:Lombok 1.16.4

* 后端

* 核心框架:Spring Framework 4.0.3

* 视图框架:Spring MVC 4.0.3

* 服务端验证:Hibernate Validator 5.1.1

* 持久层框架:MyBatis 3.2.7

* 数据库连接池:Alibaba Druid 1.0.29

* 缓存框架:Ehcache 2.10.4、Redis

* 日志管理:Logback 1.1.3

* 测试框架:Spring Test 4.0.3、Junit 4.12、Dbunit 2.5.3

* 工具类:Apache Commons、Jackson 2.8.8、Dozer 5.5.1、Jedis 2.9

* RPC框架:Dubbo 2.5.3

* 前端

* JS框架:jQuery 1.12.1、zepto.js

* 模板框架:Velocity 1.7

* 平台

* 服务器中间件:JDK1.7、Servlet3.1 下开发,支持 Tomcat8+

* 数据库支持:MySql5.*

* 开发环境:JDK1.7、IDEA、Maven3.1、Git

### 框架结构介绍

* component

* lang

* parent

* module-base

* parent-module

* common

* common-service

* uic

* uic-portal

* uic-sdk

* uic-business

* uic-service

* uic-dao

* gic

* uic-portal

* uic-sdk

* uic-business

* uic-service

* uic-dao

* auth

* auth-portal

* auth-business

* auth-service

* auth-dao

### 包名规范

* lang : cn.com.servyou.uc.lang

* dao-base : cn.com.servyou.uc.dao.base

* service-base : cn.com.servyou.uc.service.base

* portal-base : cn.com.servyou.uc.portal.base

* common-dao : cn.com.servyou.uc.dao.common

* common-service : cn.com.servyou.uc.service.common

* uic-dao : cn.com.servyou.uc.dao.uic

* uic-service : cn.com.servyou.uc.service.uic

* uic-business : cn.com.servyou.uc.business.uic

* uic-sdk : cn.com.servyou.uc.portal.uic.dubbo.sdk

* uic-portal : cn.com.servyou.uc.portal.uic

* gic-dao : cn.com.servyou.uc.dao.gic

* gic-service : cn.com.servyou.uc.service.gic

* gic-business : cn.com.servyou.uc.business.gic

* gic-sdk : cn.com.servyou.uc.portal.dubbo.sdk

* gic-portal : cn.com.servyou.uc.portal.gic

* auth-dao : cn.com.servyou.uc.dao.auth

* auth-service : cn.com.servyou.uc.service.auth

* auth-business : cn.com.servyou.uc.business.auth

* auth-portal : cn.com.servyou.uc.portal.auth

### Spring使用规范

* 在 Portal 层以下如需要使用 Spring 则把定义放入本模块 resource 目录中的 * .business.xml 或者 * .service.xml 文件中

* 在 Portal 层需要使用 Spring 则把定义放入本模块 config 包中的 WebConfig 类中。

### Dubbo开发规范

* 在 module-sdk 模块的 facade.business 包中定义 Dubbo 接口及配套的 Stub 类(用于完成客户端数据校验,减少服务端访问压力)

* 在 module-sdk 模块的 vo.business 包中定义具体接口的返回对象,该对象必须继承 cn.com.servyou.uc.portal.dubbo.sdk.base.BaseResponse 类

* 在 module-sdk 模块的 vo.business 包中定义具体接口有可能返回的错误码接口,该接口必须继承cn.com.servyou.uc.portal.dubbo.sdk.base.ResultMessage

* 在 module-sdk 模块的 base.enumeration 包中定义接口有可能用到的枚举类型,完成客户端数据校验的时候有可能会使用到

* 服务端接口配置规范,每个具体接口暴露给客户端调用前需要根据业务需要,定义以下几个配置

* version : 接口的版本号,

* stub : 接口对应的 stub 类路径

* retries : 接口重试次数(除非业务需要,默认建议设置为0)

* timeout : 接口访问超时时间

* loadbalance :重试算法,当需要重试时,该参数定义才有意义

* actives : 每服务消费者每服务每方法最大并发调用数

* executes : 服务提供者每服务每方法最大可并行执行请求数

* delay : 延迟注册服务时间(毫秒) ,设为-1时,表示延迟到Spring容器初始化完成时暴露服务,推荐设置为-1

* 异常处理 见异常使用规范章节

### Restful开发规范

### 公共组件介绍

* cn.com.servyou.uc.lang.enumeration : 定义整个 UC 系统会在POJO中用到的枚举类型,集中管理系统枚举

* cn.com.servyou.uc.lang.exception : 定义整个 UC 系统中各个子系统间传递的异常类型

* cn.com.servyou.uc.lang.format : 定义整个 UC 系统中会用到的格式化工具类,其中包含 JSON 的格式化类

* cn.com.servyou.uc.lang.reflect : 定义整个 UC 系统中会用到的基于反射的工具类,其中包含对 Dozer 进行封装的工具类

* cn.com.servyou.uc.lang.stereotype : 定义整个 UC 系统中会用到的自定义注解

* cn.com.servyou.uc.lang.test : 存放了 UC 系统最顶级的测试基类

* cn.com.servyou.uc.lang.utils : 定义 UC 系统各个模块都有可能会用到的工具类,区别于各个顶级基础模块中定义的层级工具类,一个 Scope 是整个 Project 另外的 Scope 是具体的逻辑 Module 层,公用程度不一。

* cn.com.servyou.uc.lang.validator : 定义 Hibernate Validator 校验的具体实现类,此包将由指定的 Service Owner 维护

### 业务开发规范

**逻辑层划分如下:**

* portal 业务入口层

* portal-sdk 对外提供的 RPC 访问接口

* business 业务服务层

* service 原子服务层

* dao 数据持久化层

**有以下几条约定的跨层访问规则:**

* portal-sdk 没有 parent module

* portal-sdk 对内只会被对应的 portal 层依赖

* business 层有统一的 parent 为 parent-service

* business 只会被对应的 portal 层依赖

* business 可以夸工程调用其他工程的 service 层 (存在待讨论的议题)

* service 层有统一的 parent 为 parent-service

* service 可以被对应的 business 层依赖,也可以被对应的 portal 层依赖

* dao 层有统一的 parent 为 parent-dao

* dao 只会被对应的 service 层依赖

* 以上涉及的依赖访问全部是基于接口依赖

**以下有几条程序开发约定**

* portal 层定义的 Controller 需要统一继承 BaseController, 详见 Demo

* portal 层与业务相关的 VO 定义放在 http.facade.* 包中,具体规则如下:

* 每个业务接口包含 Request、Response、Message 的定义

* Request 中需要加上规则校验,通过 Hibernate Validator 注解实现

* Response 统一继承 cn.com.servyou.uc.portal.http.base.BaseResponse 详见 Demo

* business 层需要放入 Spring 容器的类需要加上 @BusinessService 注解,详见 Demo

* service 层需要放入 Spring 容器的类需要加上 @Service 注解,详见 Demo

* dao 层需要被 MyBatis 扫描到的接口类需要加上 @MyBatisDao 注解,详见 Demo

* 所有 Redis 缓存都定义在 cn.com.servyou.baseservice.dao.base.cache.Cache 中

* Redis 缓存的工具类是 cn.com.servyou.baseservice.dao.base.cache.CacheUtil

### 异常使用规范

异常处理每个系统都会有自己的一套异常产生和异常处理的机制,UC 也不例外,有以下几条约定:

* 除非有特殊的需要,一般建议只抛出非检查型异常,以减少工程中的样板式代码,可以用 Exceptions 类中的 unchecked 方法把检查型异常转为非检查型异常,详见 Demo

* dao 层使用 Spring 提供的非检查型 DataAccessException 异常,框架会把 MyBatis 异常转换为 Spring 异常

* service 层允许抛出的异常只能为 ServiceException , 详见 Demo

* business 层允许抛出的异常只能为 BusinessException , 详见 Demo

* portal 层允许抛出的异常只能为 ConstraintViolationException , 详见 Demo

* 框架会在 portal 层捕获 ServiceException , BusinessException , ConstraintViolationException 详见 Demo

### 单元测试规范

以下几个关键环节必须被单元测试覆盖:

* dao 层暴露给 service 层的每个方法,详见 Demo

* service 层暴露给 business 或 portal 层的每个方法,详见 Demo

* business 层暴露给 portal 层的每个方法,详见 Demo

* portal 层暴露给外部调用的每个接口 ( 包括 HTTP 和 Dubbo 接口 ),详见 Demo

各层单元测试的编写规范

* dao 层单元测试类需要继承 BaseDaoTests 类,测试类以 Test 结尾

* service、business 层单元测试类需要继承 BaseServiceTest 类,测试类以 ServiceTest、BusinessTest 结尾

* portal 层 HTTP 服务的单元测试类需要继承 BaseHttpTest 类,测试类以 ControllerTest 结尾

* portal 层 Dubbo 服务的单元测试类以 FacadeTest 结尾

### 小企业日志框架引入

未完待续

### 小企业密钥机制引入

未完待续

## 功能点方案变更

本次改造对于功能方面主要包含以下几方面的优化调整:

* 持久化方案调整

* 打包生产切面代码时把页面模板替换成静态页面,发布到生产资源服务器中

### 持久化方案调整

#### 现状

为了提高数据读写的速度,目前 UC 中很多对象是放在 Redis 中,没有持久化到数据库中,随着业务的发展,服务的使用者越来越多,内存将会不断地升高。目前生产环境是购买阿里云的 Redis 云服务,目前的方案会造成业务运行一段时间后就要面临一次生产服务扩容的问题。先看一下有哪些对象以什么样的形式存放到了 Redis 中。

* String

* LIST

* HASH

* 企业 token 缓存 , key 格式为:“ct:UUID” , hashkey 格式为:{"companySessionInfo", "companyToken", "appId"}

* accessToken 缓存 , key 格式为: “UUID” , hashkey 格式为:{"sessionInfo", "refreshToken", "isHigh", "ssoToken"}

* refreshToken 缓存 , key 格式为:“UUID” , hashkey 格式为:{"sessionInfo", "accessToken", "ssoToken"}

* ssoToken 缓存 , key 格式为:“UUID”? , hashkey 格式为:{"accessTokenSet", "refreshTokenSet", "sessionInfo", "isHigh", "weixinToken"}

* code 缓存 , key 格式为:“UUID” , hashkey 格式为:{"ssoToken", "appId"}

* session 缓存 , key 格式为:“UUID” , hashkey 格式为:{"lastAccessedTime", "creationTime", "maxInactiveInterval", "sessionAttr:#Session.attributes.id}"

* token 缓存 ( Dubbo 暴露的服务 ) , key 格式为:未知 , hashkey 格式为:{ 未知 } //TODO 是否存在调整必要?

* SET

* 账户缓存 , key 为 "account_token_set_#Session.id" , values 为 accessToken

* ZSET

其他已经持久化到数据库中的对象

* String

* LIST

* HASH

* rank_dto_domain? 缓存 , key 格式为:“rank_dto_domain” , hashkey 格式为:{#DictData.code}

* industry_category_domain? 缓存 , key 格式为:“industry_category_domain” , hashkey 格式为:{#DictData.code}

* state_tax_bureau_code_domain? 缓存 , key 格式为:“state_tax_bureau_code_domain” , hashkey 格式为:{#TaxBureauCode.taxBureauCode} //TODO 此 POJO 设计是否有问题?

* local_tax_bureau_code_domain? 缓存 , key 格式为:“state_tax_bureau_code_domain” , hashkey 格式为:{#TaxBureauCode.taxBureauCode} //TODO 此 POJO 设计是否有问题,而且存放的内容和 state_tax_bureau_code_domain 一模一样?

* company_nsrsbh_id_domain? 缓存 , key 格式为:“company_nsrsbh_id_domain” , hashkey 格式为:{nsrsbh}

* company_dssh_id_domain? 缓存 , key 格式为:“company_dssh_id_domain” , hashkey 格式为:{nsrsbh}

* company_shxydm_domain? 缓存 , key 格式为:“company_shxydm_domain” , hashkey 格式为:{nsrsbh}

* company_dto_domain? 缓存 , key 格式为:“company_dto_domain” , hashkey 格式为:{#CompanyDto.id}

* nsrsbh_to_group_id_domain? 缓存 , key 格式为:“nsrsbh_to_group_id_domain” , hashkey 格式为:{nsrsbh}

* 标签缓存 , key 格式为:“t:#Account.id” , hashkey 格式为:{#AccountTag.tagCode}

* SET

* ZSET

#### 改造目标

把未曾持久化到数据库的数据全部持久化到数据库中,减少系统对 Redis 的依赖。优化现有的 Redis 中对象的存储结构、有效期及读写方式。目的是保持高性能的前提下减少 Redis 的内存占用量

#### 改造步骤

为了实现上述改造目标,从以下几方面着手进行改造

* 把 token、session、account 与 accessToken 的关联关系持久化到数据库中

* 替换原先的唯一键生成规则,从原先的 16 位减少为以后的 8 位

* 调整缓存中对象的存储结构(具体规则待讨论) //TODO

* 调整缓存中对象对象的生命周期(具体规则待讨论)//TODO

### 鉴权中心实现静态资源分离

#### 现状

单点登陆项目中的 View 层是用 Velocity Template 实现,当服务端发生一些未知异常时会导致用户界面显示 500+ 错误,用户体验不好

#### 改造目标

即使服务端发生故障也不会影响页面显示,只会在点击某个页面按钮时给出我们预先设计好的相对友好的提示,引导用户进行下一步操作或等待服务恢复

#### 改造步骤

* 编写 Template 2 Html 的转换工具类及转换服务

* 在用生产切面打包 HTTP 项目时自动执行转换操作

### 工作量评估

依赖技术框架的确定,未完待续

----

#### 待讨论的议题

* 内部讨论

* 文档中的 TODO 点

* 开放讨论

* business 可以夸工程调用其他工程的 service 层,将采用哪种方式调用?

* 内部RPC服务 & 外部RPC服务如何隔离?

* 对外提供 REST API 的标准?

* 小企业的日志框架如何引入

* 小企业的安全密钥机制如何引入

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,596评论 18 139
  • 一. Java基础部分.................................................
    wy_sure阅读 3,789评论 0 11
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,577评论 18 399
  • 爸爸前几天说要给我买本<新华字典>,过了好几天我都把字典的事儿给忘了。今天下午爸爸回来拿着一个箱子,我和弟弟打开箱...
    孙佳怡同学阅读 354评论 0 0
  • 不知何时对事的看法处於安心.
    vanhui阅读 124评论 0 0