如何做扩展
关于如何做好开放、扩展的技术架构设计和相关想法。
背景
做过相关基础工作的同学应该都比较清楚,除了工作本身之外,很大一部分在于如何支持到上层业务和扩展上。如果没有好的技术架构来支撑扩展,那么将会导致巨大的基础咨询、基础开发,也会因为没有好的隔离、抽象,导致整体的可维护性急剧下降,甚至导致线上稳定性的问题,并使业务不可用。
开放&扩展
从主体角度出发,如何做好开放,才有后续客体的扩展。所以,开放扩展是需要一体考虑的。
首先从现实的开发世界来看,已有哪些开放&扩展的方案设计。从核心、常用的软件说起,比如:
-
后端开发的大致核心流程:Eclipse IDE 开发 -> Maven / Gradle 构建 -> Docker 打包部署 -> JVM Runtime Container 运行时 -> Tomcat / Jetty Web 容器
-
前端开发的大致核心流程:VSCode 开发 -> Webpack 构建 -> NodeJS Runtime 运行时 -> Browser Renderer 渲染器
后端核心流程的开放&扩展机制
Eclipse Plugin
Eclipse Plugin 的开放与扩展,参考 A Quick-Start Tutorial to Eclipse Plug-in Development
图中举例了一个选中扩展,Eclipse 提供一个 Selection Service 的总线方式,包括代码编辑器、包浏览器、大纲浏览器等,都会触发「选中事件」,然后属性展示器或声明展示器就会监听「选中事件」,然后展示对应的属性或声明。更多事件可参考 org.eclipse.jface.viewers
简单来说,Eclipse Plugin 的开放与扩展,就是通过总线的形式,并用发布/订阅模式来实现扩展。
Maven Plugin
参考 Maven 的执行生命周期 maven-lifecycle-vs-phase-vs-plugin-vs-goal
相关的插件开发,通过指定生命周期,并配置 pom.xml 配置来实现。参考:guide-java-report-plugin-development
小结:Maven Plugin 的开放与扩展,就是通过生命周期来做扩展,生命周期即为扩展点,配置文件就是扩展点的执行逻辑和顺序,依次寻找插件扩展点并执行即可。
JVM 的 JNI 扩展
参考 JNI
$ java -Djava.library.path=/path/to/jnilib Test
JVM 的底层扩展,通过启动时加载对应的库,实现扩展。对应的库实现相关 JNI 接口,业务侧在启动的时候,注册相关的扩展 (RegisterNatives 在 static 区块声明,相当于做了一次回调并注册)并做 puclic native xx
相关声明即可被其他 Java 代码正常调用。
JNI 的扩展,是简单的接口约定 + 实现的逻辑。一个接口约定对应一个扩展点,且仅对应一个扩展实现。
Servlet Filter 扩展机制
Servlet 的机制大致如下:
Servlet Filter 机制,本身是出于解决 HTTP 请求的场景,本身具有较高的复杂度,比如:登录态、CORS 等等。所以,相关的开放与扩展机制,做得也相对成熟一些。
可以指定任意路径的 Filter,不同路径的 filter 的数量可以自由配置, 相关顺序由 web.xml 配置决定。
前端核心流程的开放&扩展机制
VSCode Extension
参考 VSCode API
VSCode 的插件机制,为了追求较高的扩展、轻量、快速反应的编辑器,整体都做了相当不错的隔离。包括主进程和渲染进程的隔离,使用 IPC/RPC 通信。
插件也通过 VSCode 的各种 Protocol 协议来实现扩展,和 Eclipse 的插件机制类似,但总体会更轻量些,也能看成是发布订阅的机制。
Webpack Plugin
Webpack 的插件实现,是基于 tapable 实现的。
总的思路是,所有包括 webpack 本身都是插件,暴露 run/emit/done 等 hooks 来扩展。
NodeJS Native
和 JNI 类似,NodeJS Native 的扩展,通过一层 interface 抽象,也是简单的接口约定 + 实现的逻辑。
相关方案小结
- IDE 和编辑器的扩展,总的是围绕「编辑」展开的,相关的扩展通过事件的发布/订阅机制实现。
- Maven、Webpack 有明确的编译生命周期,扩展的时机也较为明确,基于编译生命周期,叠加相关的代码逻辑即可。
- JVM、Node 的扩展,类似 Interface 定义的约定,运行时按某种约定的 protocol 来做调用,实现方按 protocol 来做相关实现。
参考
- 入职淘宝一年,聊聊我理解的首页&购物车
- Abstractions for Software Architecture and Tools to Support Them
- On Plug-ins and Extensible Architectures
- A Comprehensive Approach for the Development of Modular Software Architecture Description Languages
- Pluggable Systems as Architectural Pattern:An Ecosystemability Perspective
- A Core-Periphery-Legality Architectural Style for Open Source System Development