背景
随着业务的发展,技术架构也在不断的演变升级,为了实现快速、稳定的响应上层业务的需求,各个业务点也在不停的组件化,京东零售的整体技术架构纵向使用分层解藕,横向进行多业务拆分,这样极大的调动整体技术架构的灵活性,也能加快业务的迭代。就拿京东商城来说,它的需要支持的端就包含PC、M站、App、微信手Q等业务线,每条业务线下面需要融合网关系统、搜索系统、支付系统、商品系统、广告系统、促销系统、订单系统、商家系统、供应链系统、物流系统等。大体架构我们可以用一张图来说明一下。
随着系统架构的不断升级增加、组织架构的调整人员替换交接,也出现了一些问题:
1) 中台很多系统都没有测试环境,导致很多团队负责的应用无法在本地(开发人员机器)运行,开发的功能无法及时得到测试,极大的影响了需求开发的效率;
2) 由于依赖系统不存在测试环境,测试团队在接到测试需求时候,无法在测试环境对测试需求进行测试,极大的影响测试人员的工作效率;因为依赖系统没有对应的测试环境,导致目前的开发、测试模式均是将代码部署至预发环境,功能变更到部署至预发耗时较 长(公司没有成熟的CI/CD流程),导致整个需求交付周期变长。同时,研发、测试共用一套预发环境,也导致多个需求并行的的时候存在冲突,进一步降低需求交付效率。
3) 需求的排期需要牵涉更多的系统,单个需求原来需要一个团队开发完成即可上线,现在需要多个多个团队各自开发,不同团队开发的系统之间相互依赖,开发效率各不相同,很多时候,我们都在等待依赖系统提供环境然后验证自己的系统功能是否正确,整个需求交付效率就更加低效。
综合目前面临的问题,我们需要找到一款产品能解决以下几个痛点:服务依赖缺失、应用无法启动、mock接入流程复杂、手动mock的操作繁琐。Jmock平台的产生由此而来,我们可以从下图中了解Jmock平台在架构的位置:
Jmock是如何解决以上痛点我们将在下面的章节中给大家详细讲解。
一步接入
01
client的SDK接入
为了实现应用接入流程复杂,JMock的接入仅仅需要引入Maven依赖即可,完全不需要任何其他的客户端配置。
<!-- JMock refer: http://test.jmock.jd.com -->
<dependency>
<groupId>com.jd.m.mocker</groupId>
<artifactId>mocker-client</artifactId>
<version>x.x.x-beta.x</version>
</dependency>
对于需要mock的本地方法只需在方法上添加@JMock注解即可。
@JMock
public String foo(String param) {
return param;
}
另外,SDK会自动校验应用环境是否符合mock条件,如果是生产环境机器,SDK会主动关闭开关,不会产生任何不必要的性能损耗及风险。
0 2
零配置
JMock遵循零配置原则,做到尽量减少研发的使用、学习成本,JMock的零配置主要体现在3个方面:
1) 基础数据零配置:Mock所用到的接入方应用中包括使用者、应用名称等基础数据会由SDK自动获取;
2) JSF调用零配置:JMock采用JSF自身提供的扩展点支持来实现JSF调用过程的零配置,mock过程在JSF的filter层完成;
3) 应用健康监控零配置:应用的启动过程的健康情况会随Spring的生命周期由SDK上报,并自动注册第一次接入的新应用
智能mock
01
网络隔离
为了方便大家快速使用,减少用户手动mock的繁琐操作,内置了智能化的mock开关逻辑。mock-client发现当前网络不属于开发环境、测试环境的时候,会自动关闭mock。此时对应用毫无影响。
0 2
mock-client维度的mock开关
SDK维度的mock开关用来控制全局,默认开启mock,不需要配置。当用户现式的将其关闭之后,应用的mock动作直接停止,配置方法为在应用的classpath目录下新建文件mocker.properties,并写入以下配置。
<span> <span># 关闭JMock</span></span>
<span> mocker.<span>on</span>=<span>false</span></span>
03
mock-server维度的开关
在mock-server中区分应用级别的mock开关和方法级别的开关。应用级别的mock开关一旦关闭,此应用下所有的方法均不再进程mock操作;方法维度的mock开关,顾名思义就是控制当个方法是否进行mock操作,一旦关闭,只会影响这个方法是否进行mock。如果要实现智能mock,就需要将应用mock开关和方法mock开发都是开启状态,默认开启状态,再配合mock数据源控制,这个在下一节中会说到。交互关系我们通过下面一张图来进行说明:
04
数据源智能控制
mock数据来源用来控制方法返回值生成策略,也是智能mock实现的关键之一。我先说明一下几个数据源:
1) 历史数据:也称为缓存数据,也就是当项目启动的时候,上一次拉取的线上数据,保存到缓存数据表中;
2) 自动生成:强制mock操作,通过返回值模版来生成mock数据,在应用级别和方法级别都有这个数据源的控制;
3) 智能选择:智能选择是在服务优先请求服务端接口,拉取数据,如果接口不存活,就会到缓存数据表中拉取数据,如果缓存数据表也不存在,那就直接使用mock生成返回值数据;
4) 后端依赖:强制请求服务端接口拉取返回值数据;
5) 同应用来源:这个是方法数据来源中的控制中出现,如果使用这个来控制数据来源的化,那就会同步到应用级别的数据来源控制;
总体而言,私有模版的数据源控制优先级最高,接着就是应用模板数据源控制,之后是公有模板数据源的控制,最后是应用级别的数据源控制,我们可以通过以下这张图来说明它们直接的逻辑。
05
mock开关和mock数据源的关系
Mock开关控制应用、方法是否进行Mock,一旦关闭,则执行方法原有逻辑。Mock开关开启的时候,才会按照Mock数据来源的规则进行处理。通过两者灵活设置来实现mock自动化生成,如下图展示:
数据自动生成
数据的自动生成不仅减少用户需要手动配置的流程,还可以为用户自动解析并mock出日益复杂的项目依赖的服务接口,实现对接口的自动生成需要解决两方面的问题,第一是对类的结构解析,第一个就是选择一个通用的占位符规范,生成标准的json模板,再解析json模板生成客户端需要的json字符串。如下下图所示,具体的实现方式我们将在下面的内容中介绍。
01
类结构解析
1)通过JavaTypeStructParser.parse来解析类的结构和每个字段的类型
解析结果示例如下:
{
"fields": [
{
"name": "id",
"struct": {
"range": {
"max": 9223372036854775807,
"min": -9223372036854775808,
"type": "RANGE"
},
"structType": "NOR",
"targetClassName": "java.lang.Long",
"valueType": "NUM"
},
"structType": "FIELD"
},
{
"name": "appName",
"struct": {
"structType": "NOR",
"targetClassName": "java.lang.String",
"valueType": "STR"
},
"structType": "FIELD"
}
],
"structType": "OBJ",
"targetClassName": "com.jd.jone.api.v2.beans.sysapp.AppWithSysInfo"
}
2)再通过JtspTpl.parse(struct)根据每个字段类型,为字段生成对应的占位符
解析结果示例:
{
"id": "@natural",
"appName": "@last",
"@type": "com.jd.jone.api.v2.beans.sysapp.AppWithSysInfo"
}
3)通过Mockingly.mock,生成mock数据替换占位符,生成JSON格式的返回值返回给SDK。返回值示例:
{
"id": 36322613,
"appName": "White",
"@type": "com.jd.jone.api.v2.beans.sysapp.AppWithSysInfo"
}
4)SDK拿到JSON格式返回值反序列化生成Mock结果对象
02
占位符规范
占位符用于自动生成mock参数,目前有数值型、字符型、布尔型、日期型。占位符是借鉴MockJS部分占位符,不是所有的MockJS占位符都支持,占位符语法参考MockJS数据占位符定义规范。占位符 只是在属性值字符串中占个位置,并不出现在最终的属性值中。占位符 的格式为:
<span><span>@占位符</span></span>
<span><span>@占位符(参数[,参数])</span></span>
1)使用说明:
①用 @ 来标识其后的字符串是 占位符。比如:识别@first占位符,如果填成@firsttest,将识别为firsttest,需要使用@first()test才能识别。
②占位符不区分大小写。
③占位符 目前无法引用 数据模板 中的属性。
④占位符目前无法支持 相对路径 和 绝对路径。
⑤你可以同时使用多个占位符,比如例子中的‘name.full'属性值。
{
name: {
first: '@FIRST',
middle: '@FIRST',
last: '@LAST',
full: '@first @middle @last'
}
}// 填充后 =>
{
"name": {
"first": "Charles",
"middle": "Brenda",
"last": "Lopez",
"full": "Charles Brenda Lopez"
}
}
2)部分占位符展示:
3) 占位符扩展
我们在现在已经支持的占位符基础上,可以进行增删改查,定期的通过接口使用的场景,会自动将一些占位符添加到到占位符库中。
服务依赖分析
服务依赖分析能协助研发清楚知道哪些接口服务是通过mock自动生成,哪些接口是存活拉取的线上数据。应用启动之后,从client端请求到mock-server端,传递参数和方法声明,在mock-server端我们会根据传递的数据调用jsf的服务。判断接口是否存活分为两部分,首先会根据方法声明在jsf注册中心验证是否注册,如果未注册,表明该方法声明不存活,如果已经注册,就会根据该jsf接口能否在1000ms内返回方法调用预期的数据即为可用,否则也会判定为不存活,并将接口声明的存活状态反馈给研发,协助研发快速定位依赖接口的问题。操作流程如下图:
未来展望
Jmock能帮助开发和测试快速启动本地应用,实现研发人员的降本提效,同时也提供了应用依赖分析,协助开发能快速的找到接口依赖的问题。目前Jmock平台已经完成了应用mock的数据智能选择、返回值模板的管理、应用依赖分析等,后续迭代我们将重点实现mock的参数化,全链路以及与测试用例的对接。
咨询邮箱: holdsupport@jd.com
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
500 Lines or Less
Amy Brown、Michael DiBernardo / 2016-6-28 / USD 35.00
This book provides you with the chance to study how 26 experienced programmers think when they are building something new. The programs you will read about in this book were all written from scratch t......一起来看看 《500 Lines or Less》 这本书的介绍吧!