此工程已将公共部分抽离出整合成框架smart-cloud。
smart-cloud地址:https://github.com/smart-cloud/smart-cloud
smart-cloud对应示例smart-cloud-examples地址:https://github.com/smart-cloud/smart-cloud-examples
此项目为spring cloud微服务学习示例项目。所实现功能如下:
- 接口文档自动生成(服务启动时通过swagger生成原始数据,处理后上传至gitbook)
- 可以生成mock数据,充分发挥前后端分离的作用
- 部署灵活,服务可合并(合并后服务间通过内部进程通信;分开后通过rpc通信)部署
- 业务无关代码自动生成
- 接口(加密+签名)安全保证
- 业务无关功能(如日志打印、公共配置、常用工具类等)抽象为公共模块
- 支持多数据源、分表分库、分布式事务
- 敏感配置信息加密
- 单体服务开发接阶段测试不依赖其他服务(挡板测试、关闭eureka)
- 通过单元测试、集成测试、系统测试减少代码的缺陷
- 代码安全保护
- 技术栈稳定、实用、易用
模块 项目名 说明 端口 公共配置 common 日志切面、rpc测试挡板、接口mock数据、公共实体对象、工具类、公共拦截器、log4j2日志模板等 – 代码生成 demo-code-auto-generate 自动生成entity、dao、biz、service、controller、公共配置等业务无关代码 – 服务注册中心 demo-eureka-module 服务注册中心模块父项目 – eureka-nodeA eureka节点A 10001 eureka-nodeB eureka节点B 10002 电商模块 demo-mall-module 电商模块父项目 – demo-mall-order-service 订单服务 20011 demo-mall-product-service 商品服务 20021 demo-mall-user-service 用户服务(用户、登陆等) 20031 demo-mall-auth-service 权限服务 20041 电商模块rpc接口 demo-mall-rpc 包括请求、响应对象、rpc接口 – ORM demo-mapper-common mybatis、mapper、sharding jdbc、seata等封装。业务无关mapper动态生成,sql日志打印等 – 系统测试模块 demo-system-test-module 系统测试模块父项目 – demo-mall-system-test 商城系统测试 – 服务合并模块 demo-merge-module 合并模块父项目 – demo-merge-mall 电商合并服务 30001 服务监控 spring-boot-admin – 10011 服务网关 spring-cloud-gateway – 80 相关文档 docs 服务相关sql、文档图片等 –
名称 | 说明 |
---|---|
spring boot | 手脚架 |
spring cloud gateway | 服务网关 |
eureka | 服务注册 |
spring boot admin | 服务监控 |
携程apollo | 配置中心 |
openfeign | 声明式服务调用 |
sleuth、log4j2 | 链路追踪、日志 |
mybatis 、mapper | ORM |
seata | 分布式事务 |
sharding jdbc | 分库分表 |
redis | 缓存 |
rocketmq | 消息队列 |
fastdfs | 文件存储 |
xxl-job | 定时任务 |
easyexcel | excel导入导出 |
Hibernator-Validator | 参数校验 |
mockito | 单元测试 |
swagger、gitbook | 接口文档 |
xjar | 代码安全 |
jasypt-spring-boot | 配置文件中敏感数据加解密 |
Lombok | 简化代码 |
技术 | 说明 |
---|---|
Vue | 前端框架 |
Vue-router | 路由框架 |
Vuex | 全局状态管理框架 |
Element | 前端UI框架 |
mpvue | 基于 Vue.js 的小程序开发框架 |
Axios | 前端HTTP框架 |
Js-cookie | cookie管理工具 |
nprogress | 进度条控件 |
quicklink | 在空闲时预取viewport内的链接来加快后续页面的加载速度 |
Font Awesome | 图标 |
仅支持http get、http post两种方式。
对于http get,请求参数只签名;响应信息加密,且签名。
对于http post,请求响应皆加密,且签名。
接口mapping url格式:接口使用端标志/接口类型标志/服务模块名/接口模块名/接口名
如:api/sign/user/loginInfo/login
接口使用端标记:
api:app端使用的接口
oms:管理后台使用的接口
rpc:rpc接口
接口分为4种:
open:既不登陆,亦不签名加密
sign:不需登陆,需签名加密
identity:需登陆,不签名加密,需鉴权
auth:需登陆,需签名加密,需鉴权
http get、http post共同部分,即http headers部分的数据,它包含请求时间戳(默认2分钟内有效)、请求的token、交易流水号、签名等4个自定义字段:
smart-sign: 109ad1a8e05f8de345e6d780f09b001e97dc3d6fa9bbbe6936edb2b75a81864ac3b0b071e093af001fbffa479217540138b98f6f165e8246dd25a2536649f1f6
smart-timestamp: 1555778393862
smart-token: 4c2e22605001000rK
smart-nonce: eb9f81e7cee1c000
请求数据由http headers、url查询字符串组成,url查询字符串为实际请求的参数。
如http://localhost:10010/api/open/user/loginInfo/queryById?id=100
请求数据采用json格式,通过流的形式传输。
请求数据由http headers、http body两部分组成,http body部分为请求的实际参数(json格式)。
http body部分
{
"products": [{
"buyCount": 1,
"productId": 4
}]
}
{
"head": {
"transactionId": null,
"code": "100200",
"msg": "成功",
"timestamp": 0
},
"body": {
"id": "2",
"name": "手机",
"price": "1200"
},
"sign": "109ad1a8e05f8de345e6d780f09b001e97dc3d6fa9bbbe6936edb2b75a81864ac3b0b071e093af001fbffa479217540138b98f6f165e8246dd25a2536649f1f6"
}
1、C(客户端)请求S(服务端);
2、S端随机产生两对rsa公钥、私钥(clientPriKey、serverPubKey;clientPubKey、serverPriKey),以及token,并返回token、clientPubKey、clientPriKey给C端;
3、C端保存“token、clientPubKey、clientPriKey”,并随机生成aes加密的key;
4、C端将aesKey用clientPubKey加密,用clientPriKey签名并发送给S端;
5、S端校验签名并解密,保存aesKey;
6、后续C端与S端通信,将会用aesKey加解密;C端用clientPriKey签名,用clientPubKey校验签名;S端用serverPriKey签名,用serverPubKey校验签名。
Http Get请求方式 :
1.url查询字符串中的参数以json的格式组装得到查询的json串;
2.sign = RSA签名(“httpmethod + http headers(按自然排序的json串) + url查询json串”组成)
Http Post请求方式 :
1.将http body部分的数据json化;
2.AES加密body的json串;
3.sign = RSA签名(“httpmethod + http headers(按自然排序的json串) + AES加密body的json串”)
Http Get、Http Post方式响应信息加密、签名相同。
1.校验签名是否正确;
2.解密数据
head = AES解密(head的json串)
body = AES解密(body json串)
Http Get请求方式 :
校验签名是否正确
sign = RSA签名校验(“httpmethod + http headers(按自然排序的json串) + url查询的json串”组成,sign, 公钥)
Http Post请求方式 :
1.校验签名是否正确
sign = RSA签名校验(“httpmethod + http headers(按自然排序的json串) + AES加密body的json串”, 公钥)
2.AES解密body的json串;
Http Get、Http Post请求方式响应信息加密、签名相同。
head = AES加密(head的json串)
body = AES加密(body json串)
sign = RSA签名签名(AES加密(head的json串) + AES加密(body json串))
单个服务以jar的形式,通过maven引入合并服务中。在单体服务中,feign接口通过http请求;服务合并后,feign接口通过内部进程的方式通信。
1. 定义单数据源properties对象SingleDataSourceProperties,多数据源配置数据以Map<String, SingleDataSourceProperties>的形式从yml文件中读取;
2. 手动(通过new方式)构建所有需要的bean对象;
3. 手动将bean注入到容器中。
多数据源配置示例:
smart:
data-sources:
product:
url: jdbc:mysql://127.0.0.1:3306/demo_product?characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=Asia/Shanghai
username: root
password: 123456
mapper-interface-location: com.liyulin.demo.mall.product.mapper
mapper-xml-location: classpath*:com/liyulin/demo/mall/product/mybatis/**.xml
order:
url: jdbc:mysql://127.0.0.1:3306/demo_order?characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=Asia/Shanghai
username: root
password: 123456
mapper-interface-location: com.liyulin.demo.mall.order.mapper
mapper-xml-location: classpath*:com/liyulin/demo/mall/order/mybatis/**.xml
自定义条件注解封装FeignClient。使其在单体服务时,rpc走feign;在合体服务时,rpc走内部进程通信。
自定义注解YamlScan,用来加载配置的yaml文件(支持正则匹配)。通过SPI机制,在spring.factories文件中添加EnvironmentPostProcessor的实现类,通过其方法参数SpringApplication获取启动类的信息,从而获取YamlScan注解配置的yaml文件信息。然后将yaml文件加到ConfigurableEnvironment中。
自定义条件注解SmartSpringCloudApplicationCondition,只会让启动类标记的启动注解生效。
合体服务打包时,单体服务依赖的包也打进单体服务jar。通过maven profiles解决
接口通过切面拦截的方式,通过反射可以获取返回对象的所有信息,然后根据对象的属性类型,可以随机生成数据;对于特定要求的数据,可以制定mock规则,生成指定格式的数据。
利用单元测试,提高测试覆盖率。
在集成测试下,关闭eureka,减少依赖。
依赖的服务rpc接口,通过mockito走挡板。
通过事务回滚,还原Test case对DB的修改。
接口文档由三个步骤自动生成:
- 通过swagger自动生成接口文档的json格式数据;
- 将json格式数据转化为markdown格式;
- 在服务启动时将markdown格式数据上传(可根据配置的开关控制是否上传)到gitbook。
如果选用的注册中心是eureka,那么就推荐@EnableEurekaClient,如果是其他的注册中心,那么推荐使用@EnableDiscoveryClient。
比如src/main/resources下有application-email.yml、application-mq.yml等文件,在yaml中添加
spring:
profiles:
include: email,mq
或
spring:
profiles:
include:
- 子项1
- 子项2
- 子项3
日志打印pattern中加入
[%X{X-B3-TraceId},%X{X-B3-SpanId},%X{X-B3-ParentSpanId},%X{X-Span-Export}]
各字段解释:
- TraceId为此次调用链共享id;
- SpanId本应用唯一id;
- ParentSpanId为上级应用唯一id;
- X-Span-Export是否是发送给Zipkin。
Spring Cloud Sleuth可以追踪10种类型的组件:async、Hystrix、messaging、websocket、rxjava、scheduling、web(Spring MVC Controller,Servlet)、webclient(Spring RestTemplate)、Feign、Zuul。
例如scheduling
原理是AOP(TraceSchedulingAspect、TraceSchedulingAutoConfiguration)处理Scheduled注解,只要是在IOC容器中的Bean带有@Scheduled注解的方法的调用都会被sleuth处理。
其他组件实现见包org.springframework.cloud.sleuth.instrument。
- 更改hosts文件,添加如下内容
127.0.0.1 nodeA
- 安装redis,并启动
- 安装mysql,执行/docs/sql下脚本
- 安装seata服务端,下载地址https://github.com/seata/seata/releases
- 服务启动(先启动eureka,然后依次启动mall下服务)
- 针对jasypt加密,所有的需要合并的单体服务的jasypt.encryptor.password的值必须相同,否则会报错。
- 关于seata
1、seata目前不支持“allowMultiQueries=true”,一次执行多条sql会报错。
2、seata服务端以file方式存储;以db方式存储会报错。
- 服务构建
单体服务构建:clean install
合体服务构建:clean install -P merge
Leave a Reply