建设一个网站大概费用,做别墅花园绿化的网站,接网站建设_网站设计,企业网站排名提升软件优化背景
公司成立以来#xff0c;积累了数以万计的可复用接口。上层的SaaS业务#xff0c;原则上要复用这些接口开发自己的业务#xff0c;为了屏蔽调用接口的复杂性#xff0c;基础服务开发了apisdk组件#xff0c;定义了一套声明OpenAPI的注解、注解解析器#xff0c;实例…背景
公司成立以来积累了数以万计的可复用接口。上层的SaaS业务原则上要复用这些接口开发自己的业务为了屏蔽调用接口的复杂性基础服务开发了apisdk组件定义了一套声明OpenAPI的注解、注解解析器实例化OpenAPI的工具封装了签名算法同时提供了查询域名、查询参与签名的secret、获取Token等基础服务。不同场景的OpenAPI如App端和Web端需要调用不同的基础服务。
这套apisdk组件经过了多年的应用功能上完全hold住业务需求然而问题来了。
公司在疫情这几年的经济效益实在太差我做这期分享前裁了50%可能有人猜到是哪家公司当然大多数的互联网公司都有裁员的动作。那裁员之后的业务谁来做公司战略是交给外包。
但是我们的业务完全依赖基础服务的自研网关、用户体系、接口暴露组件、apisdk组件、基础服务等外包要承接业务必须要学会这套东西。但这些东西封装的并不完善简单来说都不是傻瓜式的对外包来说成本太高。别说外包了业务部门说直白一点是面向接口编程对新入职的同学学习成本高开发效率低。
于是为了让一切变得傻瓜式我承担了网关接口暴露组件、apisdk的二次封装。此次分享内容主要以apisdk为主涉及的技术/内容Springboot拓展点的应用、自定义Spring扫描、Spring IoCFactoryBean、JDK动态代理、aop源码拓展、javassist字节码技术等。
注分享的源码全部是自己代码借鉴了Spring注解、aop等源码不含公司成分目的是分享这些技术的实战。
apisdk组件
apisdk组件包括了开放接口声明、签名算法、Http执行器okhttp3、响应数据解析等模块其中接口声明、参与签名的参数需要开发者提供开发者调用接口方法触发Http执行器发起接口调用。
二次封装原因除了学习成本高它还是java和kotlin混用原作者早已离职维护困难只能在原基础上做封装。
下面截图是原始的apisdk和二次封装后的apisdk使用方式的对比通过截图大家会对开放接口的声明、请求上下文构建、接口调用方式有一定的认识有助于大家理解屏蔽了哪些操作。
接口声明
原接口声明 接口声明必须要有SdkContext固定参数接口调用前必须手动调用基础服务构造SdkContext上下文这样才能正确的发起调用。
二次封装后接口声明 二次封装后由底层完成了SdkContext参数的自动填充。
接口调用
原调用方式 上面是模拟调用的过程包括接口实例化、SdkContext封装、接口调用实际的调用过程比这个复杂的多。
二次封装后接口调用方式 apisdk二次封装介绍
二次封装涉及到的技术自定义自动装配、自定义Spring扫描、Spring IoCFactoryBean、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可以生成接口的代理对象二次封装后我提供了JdkDynamicAopProxyA和B对象由这两个工具来生成代理SdkManager生成B的对象JdkDynamicAopProxy生成A的对象并且A对象由一些列的拦截动作。
Aop源码拓展
二次封装最重要的是在A对象的方法执行过程中前置拦截生成SdkContext并调用B对象。拦截的实现是抽取Spring aop的api形成独立的Api目的是离开Spring仍然可以运行。
Aop的变动包括扩展MethodBeforeArgsChangeableAdvice参数可变的前置拦截动态构建方法参数。
其他
Environment
FactoryBeanproperty-placeholder
EnvironmentPostProcessor
ApplicationContextInitializer
BeanFactoryPostProcessor
工程结构 工程结构如上图其中
access-boot-apisdk模拟apisdk包括OpenAPI声明注解、注解解析器实例化OpenAPI的工具封装了签名算法等access-boot-autoconfigureapisdk二次封装核心access-boot-dependencies依赖管理access-boot-starter-sample业务开发Demoaccess-boot-starters启动器依赖
分享内容来自此工程大家请参考 码云。
注意
之后的blog我会按照以下规则介绍。 开发者定义的接口声明我称作为原始接口、A接口、A javassist生成的接口声明我称作为增强接口、内存接口、B接口、B