OpenAPI SDK组件介绍
背景
公司成立以来,积累了数以万计的可复用接口。上层的SaaS业务,原则上要复用这些接口开发自己的业务,为了屏蔽调用接口的复杂性,基础服务开发了apisdk组件,定义了一套声明OpenAPI的注解、注解解析器,实例化OpenAPI的工具,封装了签名算法,同时提供了查询域名、查询参与签名的secret、获取Token等基础服务。不同场景的OpenAPI,如App端和Web端,需要调用不同的基础服务。
这套apisdk组件经过了多年的应用,功能上完全hold住业务需求,然而问题来了。
公司在疫情这几年的经济效益实在太差,我做这期分享前,裁了50%(可能有人猜到是哪家公司),当然大多数的互联网公司都有裁员的动作。那裁员之后的业务谁来做?公司战略是交给外包。
但是我们的业务完全依赖基础服务的自研网关、用户体系、接口暴露组件、apisdk组件、基础服务等,外包要承接业务,必须要学会这套东西。但这些东西封装的并不完善,简单来说,都不是傻瓜式的,对外包来说成本太高。别说外包了,业务部门说直白一点,是面向接口编程,对新入职的同学,学习成本高,开发效率低。
于是,为了让一切变得傻瓜式,我承担了网关接口暴露组件、apisdk的二次封装。此次分享内容主要以apisdk为主,涉及的技术/内容:Springboot拓展点的应用、自定义Spring扫描、Spring IoC(FactoryBean)、JDK动态代理、aop源码拓展、javassist字节码技术等。
注:分享的源码全部是自己代码,借鉴了Spring注解、aop等源码,不含公司成分,目的是分享这些技术的实战。
apisdk组件
apisdk组件包括了开放接口声明、签名算法、Http执行器(okhttp3)、响应数据解析等模块,其中接口声明、参与签名的参数需要开发者提供,开发者调用接口方法,触发Http执行器发起接口调用。
二次封装原因:除了学习成本高,它还是java和kotlin混用,原作者早已离职,维护困难,只能在原基础上做封装。
下面截图是原始的apisdk和二次封装后的apisdk使用方式的对比,通过截图,大家会对开放接口的声明、请求上下文构建、接口调用方式有一定的认识,有助于大家理解屏蔽了哪些操作。
接口声明
原接口声明

接口声明必须要有SdkContext固定参数,接口调用前,必须手动调用基础服务构造SdkContext上下文,这样才能正确的发起调用。
二次封装后接口声明

二次封装后,由底层完成了SdkContext参数的自动填充。
接口调用
原调用方式

上面是模拟调用的过程,包括接口实例化、SdkContext封装、接口调用,实际的调用过程比这个复杂的多。
二次封装后接口调用方式

apisdk二次封装介绍
二次封装涉及到的技术:自定义自动装配、自定义Spring扫描、Spring IoC(FactoryBean)、JDK动态代理、aop源码拓展、javassist字节码技术等。下面简单的介绍下二开的思路及相关的技术点。
思路
原始接口声明必须要定义SdkContext参数,必须要手动调用多个服务创建SdkContent,必须要手动声明接口实例。据我了解:
- 公司不允许跨区域(域名)调用开放接口,如不允许中国区调用美国区暴露的接口。
- 调用开放接口一定要有SdkContext参数
- SdkContext构建的步骤是固定的,但涉及的服务较多
综上,域名问题可以通过部署环境动态获取(已有服务);开发者可以不定义SdkContext参数,底层通过字节码技术动态新增SdkContext方法参数;底层拓展aop的advice,方法执行前构建SdkContext参数;实现Spring扫描组件,通过FactoryBean实例化接口,开发者使用注解即可完成Bean对象的依赖。
涉及技术
自定义自动装配
自研boot启动器,主要是@Import的应用,在apisdk中是Spring自定义扫描的入口。
自定义Spring扫描
利用Spring扫描,把开放接口的声明解析成BeanDefinition,随后由Spring进行Bean的实例化。
apisdk自研框架与Spring整合(FactoryBean)
开放接口的BeanDefinition是接口,无法实例化,因此需要替换BeanDefinition的beanClass,由FactoryBean触发Bean的实例化,生成代理对象,通过FactoryBean#getObject方法将代理对象注册到IoC中。
javassist字节码
FactoryBean生成开放接口(A)的代理对象前,使用javassist生成全新的内存类(B),复制A的方法,并在每个方法上添加SdkContext参数,这样形成了A和B的映射关系。
Jdk动态代理
原始接口A和内存接口B,他们的实例化必须由动态代理支持,A和B的代理对象是怎么样的关系?
开发者使用A的代理对象,调用的方法都是没有SdkContext方法的,底层真正执行时,会围绕对象A做一些列的拦截动作,得到SdkContext,随后底层拿到B对象,调用方法并传递SdkContext。
上面对比的截图,读者知道有SdkManager可以生成接口的代理对象,二次封装后,我提供了JdkDynamicAopProxy,A和B对象由这两个工具来生成代理,SdkManager生成B的对象,JdkDynamicAopProxy生成A的对象,并且A对象由一些列的拦截动作。
Aop源码拓展
二次封装最重要的是:在A对象的方法执行过程中前置拦截,生成SdkContext,并调用B对象。拦截的实现是抽取Spring aop的api,形成独立的Api,目的是离开Spring仍然可以运行。
Aop的变动包括:扩展MethodBeforeArgsChangeableAdvice参数可变的前置拦截,动态构建方法参数。
其他
Environment
FactoryBean&property-placeholder
EnvironmentPostProcessor
ApplicationContextInitializer
BeanFactoryPostProcessor
工程结构

工程结构如上图,其中
- access-boot-apisdk:模拟apisdk,包括OpenAPI声明注解、注解解析器,实例化OpenAPI的工具,封装了签名算法等
- access-boot-autoconfigure:apisdk二次封装核心
- access-boot-dependencies:依赖管理
- access-boot-starter-sample:业务开发Demo
- access-boot-starters:启动器依赖
分享内容来自此工程,大家请参考 码云。
注意
之后的blog,我会按照以下规则介绍。
-
开发者定义的接口声明,我称作为原始接口、A接口、A
-
javassist生成的接口声明,我称作为增强接口、内存接口、B接口、B
相关文章:
OpenAPI SDK组件介绍
背景 公司成立以来,积累了数以万计的可复用接口。上层的SaaS业务,原则上要复用这些接口开发自己的业务,为了屏蔽调用接口的复杂性,基础服务开发了apisdk组件,定义了一套声明OpenAPI的注解、注解解析器,实例…...
【Java】Synchronized锁原理和优化
一、synchronized介绍 synchronized中文意思是同步,也称之为”同步锁“。 synchronized的作用是保证在同一时刻, 被修饰的代码块或方法只会有一个线程执行,以达到保证并发安全的效果。 synchronized是Java中解决并发问题的一种最常用的方法…...
西北工业大学2020-2021学年大物(I)下期末试题选填解析
2 位移电流。磁效应服从安培环路,热效应不服从焦耳-楞次定律。注意,它是变化的电场而非磁场产生。3 又考恒定磁场中安培环路定理。4感生电场5 麦克斯韦速率分布函数。6 相同的高温热源和低温热源之间的一切可逆热机的工作效率相等,无论工质如…...
PHP - ChatGpt API 接入 ,代码,亲测!(最简单!)
由于最近ChatGpt 大火,但是门槛来说是对于大家最头疼的环节, 我自己也先开发了一个个人小程序!大家可以访问使用下, 由此ChatGpt 有一个API 可以仅供大伙对接 让我来说下资质: 1:首先要搞得到一个 ChatGp…...
物联网MQTT协议简单介绍
物联网曾被认为是继计算机、互联网之后,信息技术行业的第三次浪潮。随着基础通讯设施的不断完善,尤其是 5G 的出现,进一步降低了万物互联的门槛和成本。物联网本身也是 AI 和区块链应用很好的落地场景之一,各大云服务商也在纷纷上…...
Dubbo 源码解读:负载均衡策略
概览 org.apache.dubbo包下META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.LoadBalance中内部spi实现类有以下几种: randomorg.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance roundrobinorg.apache.dubbo.rpc.cluster.loadbalance.RoundRobinL…...
吃瓜教程笔记—Task04
神经网络 知识点 M-P神经元 模型如图所示: 神经元的工作机理:神经元接收来到n个其他神经元传递过来的输入信号,这些输入信号通过带权重的连接进行传递,神经元接收到的总输入值将与神经元的阈值进行比较,然后通过…...
进程地址空间(虚拟地址空间)
目录 引入问题 测试代码 引入地址空间 故事1: 故事二: 解决问题 为什么有虚拟地址空间 扩展 扩展1(没有地址空间,OS如何工作) 扩展2 (代码只读深入了解) 扩展3(malloc本质…...
【项目精选】基于Vue + ECharts的数据可视化系统的设计与实现(论文+源码+视频)
今天给小伙伴们推荐一款超优秀的全新Vue3.0大数据系统Vue3-bigData。 点击下载源码 vue3-bigdata 基于vue3.0echarts构建的可视化大屏图表展示系统。包括各种可视化图表及Vue3新API使用。 功能 柱状图、饼图、词云图、漏斗图 水球图、折线图 仪表盘、雷达图 矩形树图、关系…...
JavaScript Window Screen
文章目录JavaScript Window ScreenWindow ScreenWindow Screen 可用宽度Window Screen 可用高度JavaScript Window Screen window.screen 对象包含有关用户屏幕的信息。 Window Screen window.screen对象在编写时可以不使用 window 这个前缀。 一些属性: screen…...
【双重注意机制:肺癌:超分】
Dual attention mechanism network for lung cancer images super-resolution (肺癌图像超分辨率的双重注意机制网络) 目前,肺癌的发病率和死亡率均居世界恶性肿瘤之首。提高肺部薄层CT的分辨率对于肺癌筛查的早期诊断尤为重要。针对超分辨…...
各种中间件的使用
init background 这一部分我们学习一些常用的, 但是不需要深入理解的中间件 , 例如kafka ,分布式文件系统。 summary Content what is kafka? What time to used it ? 其实消息队列就是解决系统之间复杂交互例如聊天系统和交易系统, …...
Systemverilog覆盖率的合并和计算方式
在systemverilog中,对于一个covergroup来说,可能会有多个instance,我们可能需要对这些instance覆盖率进行操作。 只保存covergroup type的覆盖率,不需要保存instance-specified的覆盖率coverage type和instance-specified的覆盖率…...
(周末公众号解读系列)2000字-视觉SLAM综述
参考链接:https://mp.weixin.qq.com/s?__bizMzg2NzUxNTU1OA&mid2247528395&idx1&sn6c9290dd7fd926f11cbaca312fbe99a2&chksmceb84202f9cfcb1410353c805b122e8df2e2b79bd4031ddc5d8678f8b11c356a25f55f488907&scene126&sessionid1677323905…...
力扣29-两数相除
29. 两数相除 给你两个整数,被除数 dividend 和除数 divisor。将两数相除,要求 不使用 乘法、除法和取余运算。 整数除法应该向零截断,也就是截去(truncate)其小数部分。例如,8.345 将被截断为 8 &#x…...
【MindSpore】安装和使用MindSpore 2.0.0版本简单实现数据变换Transforms功能
本篇文章主要是讲讲MindSpore的安装以及根据官方提供的例子实现数据变换功能。 昇思MindSpore是一款开源的AI框架,旨在实现易开发、高效执行、全场景覆盖三大目标。 目录1、加入MindSpore社区2、安装前准备2.1、获取安装命令2.2、安装pip2.3、确认系统环境3、安装Mi…...
PRML笔记4-绪论中推断和决策小结
在推断阶段使用训练数据学习后验概率p(Ck∣x)p(\mathcal{C_k}|\boldsymbol{x})p(Ck∣x)的模型;在决策阶段使用后验概率进行最优的分类;亦或是同时解决推断和决策问题,简单的学习一个函数f(x)f(\boldsymbol{x})f(x),将输入x\bold…...
DSPE-PEG-Streptavidin;Streptavidin-PEG-DSPE;磷脂聚乙二醇链霉亲和素,科研用试剂
DSPE-PEG-Streptavidin 中文名称:二硬脂酰基磷脂酰乙醇胺-聚乙二醇-链霉亲和素 中文别名:磷脂-聚乙二醇-链霉亲和素;链霉亲和素PEG磷脂 英文常用名:DSPE-PEG-Streptavidin;Streptavidin-PEG-DSPE 外观:粉…...
Java中的Stream
Stream流的特点 中间操作返回的是Stream类型,终结操作返回的是void 中间操作的这个Lazy指的是增加待处理操作,而不会真的处理(放队列里),集合中的数据并未实际改变,到终结操作的时候才会把这些放队列里的操…...
【数据库】关系数据理论
第六章关系数据理论 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r9ETJ75y-1677334548439)(imgs/image-20220508202554924.png)] 数据依赖 是一个关系内部属性与属性之间的一种约束关系 函数依赖多值依赖 函数依赖 [外链图片转存失败,源站可…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
Ubuntu系统多网卡多相机IP设置方法
目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机,交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息,系统版本:Ubuntu22.04.5 LTS;内核版本…...
数据结构:递归的种类(Types of Recursion)
目录 尾递归(Tail Recursion) 什么是 Loop(循环)? 复杂度分析 头递归(Head Recursion) 树形递归(Tree Recursion) 线性递归(Linear Recursion)…...
