阿里再开源!基于JAVA的模块化开发框架JarsLink

简介:

需求背景

8481c8f592b7f349aa84a1de5c171db681516edf 应用拆分的多或少都有问题。多则维护成本高,每次发布一堆应用。少则拆分成本高,无用功能很难下线。
8481c8f592b7f349aa84a1de5c171db681516edf 故障不隔离。当一个系统由多人同时参与开发时,修改A功能,可能会影响B功能,引发故障。
8481c8f592b7f349aa84a1de5c171db681516edf 多分支开发引发冲突。多分支开发完之后合并会产生冲突。
8481c8f592b7f349aa84a1de5c171db681516edf 牵一发动全身。一处核心代码的改动,或一个基础Jar的升级需要回归整个系统。
8481c8f592b7f349aa84a1de5c171db681516edf 升级和迁移成本高。中间件升级每个应用都有升级成本。

模块化开发的好处

8cad557d4753b1803698c955b6ce5bdd0eb64cc8

8481c8f592b7f349aa84a1de5c171db681516edf 可插拔,一个应用由多个模块组成,应用里的模块可拆和合,模块可快速在多个系统中迁移和部署。
8481c8f592b7f349aa84a1de5c171db681516edf 模块化开发,模块之间互相隔离,实现故障隔离。
8481c8f592b7f349aa84a1de5c171db681516edf 一个模块一个分支,不会引发代码冲突。
8481c8f592b7f349aa84a1de5c171db681516edf 在模块中增加或修改功能,只会影响当前模块,不会影响整个应用。
8481c8f592b7f349aa84a1de5c171db681516edf 动态部署,在运行时把模块部署到应用中,快速修复故障,提高发布效率。
8481c8f592b7f349aa84a1de5c171db681516edf 多版本部署,可以在运行时同时部署某个模块的新旧版本,进行AB TEST。
8481c8f592b7f349aa84a1de5c171db681516edf 减少资源消耗,通过部署模块的方式减少应用数量和机器数量。

JarsLink的应用场景

8481c8f592b7f349aa84a1de5c171db681516edf 数据管理中心,如果你需要开发一个数据管理系统,这个系统需要去不同的异构系统采集数据,这些系统会提供不同类型的接口,如RPC,HTTP等。并且数据采集的数据源多,每种数据源都需要对接和开发,数据质量比较差,需要经常修改代码进行发布。在这种场景下,通过模块化开发,实现一个数据源使用一个模块进行对接,上线新数据源只需要新增模块,修改BUG只需要修改某个模块,并能快速上线。
8481c8f592b7f349aa84a1de5c171db681516edf 后台管理系统,互联网应用发展到一定阶段会出现很多后台需求,如客服查询用户的信息帮助解答问题,开发查后台数据排查系统BUG,运营使用后台功能发送运营活动等。这些功能发布频率会大于核心系统,如果放在核心系统里会影响其稳定性,所以我们必须要建一个后台系统来开发后台功能,但是这样又带来一个新的问题,很多开发都会来这个系统进行开发,拉多分支造成代码冲突,A业务的BUG影响到B业务。所以如果每个业务线一个模块,每个模块使用一个单独的分支进行开发,就能进行隔离开发,提高开发速度,开发完后在运行时加载到系统中。
8481c8f592b7f349aa84a1de5c171db681516edf 微服务集成测试, 目前一个微服务是一个FAT JAR,如果有几十个微服务,则需要启动很多进程,DEBUG端口会很多,使用JarsLink框架合并FAT JAR,再路由请求到其他JAR,就可以只启动一个进程进行DEBUG测试。
8481c8f592b7f349aa84a1de5c171db681516edf 指标计算系统,可以把消息转发到不同的模块中进行处理,并输出指标。

目前蚂蚁金服微贷事业部几个系统和几十个模块已经使用JarsLink框架。

JarsLink的特性

隔离性

8481c8f592b7f349aa84a1de5c171db681516edf 类隔离:框架为每个模块的Class使用单独的ClassLoader来加载,每个模块可以依赖同一种框架的不同的版本。
8481c8f592b7f349aa84a1de5c171db681516edf 实例隔离:框架为每个模块创建了一个独立的Spring上下文,来加载模块中的BEAN,实例化失败不会影响其他模块。
8481c8f592b7f349aa84a1de5c171db681516edf 资源隔离:后续会支持模块之间的资源隔离,每个模块使用独立的CPU和内存资源。

动态性

8481c8f592b7f349aa84a1de5c171db681516edf 动态发布:模块能在运行时动态加载到系统中,实现不需要重启和发布系统新增功能。支持突破双亲委派机制,在运行时加载父加载器已经加载过的类,实现模块升级依赖包不需要系统发布。
8481c8f592b7f349aa84a1de5c171db681516edf 动态卸载:模块能在运行时被动态卸载干净,实现快速下线不需要功能。

易用性

提供了通用灵活的API让系统和模块进行交互。

实现原理

模块加载

JarsLink为每个模块创建一个新的URLClassLoader来加载模块。并且支持突破双亲委派,设置了overridePackages的包将由子类加载进行加载,不优先使用父类加载器已加载的。

模块的卸载

卸载模块需要满足三个条件:

8481c8f592b7f349aa84a1de5c171db681516edf 模块里的实例对象没有被引用
8481c8f592b7f349aa84a1de5c171db681516edf 模块里的Class没有被引用
8481c8f592b7f349aa84a1de5c171db681516edf 类加载器没有被引用

所以需要做到三点卸载实例,卸载类和卸载类加载器,整个模块的卸载顺序如下:

36f23537363c7642fc76b5f0e7ad2ef2aab1855e
8481c8f592b7f349aa84a1de5c171db681516edf 关闭资源:关闭HTTP连接池或线程池。
8481c8f592b7f349aa84a1de5c171db681516edf 关闭IOC容器:调用applicationContext.close()方法关闭IOC容器。
8481c8f592b7f349aa84a1de5c171db681516edf 移除类加载器:去掉模块的引用。
8481c8f592b7f349aa84a1de5c171db681516edf 卸载JVM租户(开发中):卸载该模块使用的JVM租户,释放资源。

模块间隔离

模块化开发需要解决隔离性问题,否则各模块之间会互相影响。模块之间的隔离有三个层次:

8481c8f592b7f349aa84a1de5c171db681516edf 类隔离:为每个模块创建一个类加载器来实现类隔离。
8481c8f592b7f349aa84a1de5c171db681516edf 实例隔离:为每个模块创建一个新的IOC容器来加载模块里面的BEAN。
8481c8f592b7f349aa84a1de5c171db681516edf 资源隔离:对每个模块只能使用指定的CPU和内存。

目前JarsLink实现了类隔离和实例隔离,资源隔离准备引入ALIJVM多租户来解决。

ccbfd650e876205353ece8e646f230c09bfcf470

模块间通讯

模块之间的通讯也有三种方式,RPC,本地调用,深克隆/反射。

16e0be77f859a10e8aff8535362b0c8a9e50b1d6
8481c8f592b7f349aa84a1de5c171db681516edf 本地调用:目前JarsLink的doAction就是使用的这种通讯方式,这种方式要求模块的类加载器是父子关系,且IOC容器也是父子容器。
8481c8f592b7f349aa84a1de5c171db681516edf RPC调用:用于跨JVM的模块之间调用,利用SOFA 4动态API在模块中发布和引用TR服务来实现。
8481c8f592b7f349aa84a1de5c171db681516edf 深克隆/反射:深克隆其他模块的入参,反射其他模块的方法实现调用。

类加载机制

OSGI类加载机制的关系采用的是网状结构,每个模块通过 Export-Package 来声明我要给别人用哪些类,通过 Import-Package来声明我要用别人的哪些类。JarsLink采用扁平化管理,每个模块都有一个共同的父类,这个父类加载器就是加载ModuleLoader类的加载器,如果是SOFA应用,模块的父加载器是KernelAceClassLoader,类加载器关系如下:

f00a76b838a0de70ed59de7287ba9dd62099d629

如果所有模块都需要使用的类,可以通过KernelAceClassLoader加载,如果是SOFA系统可以通过POM引入。

JarsLink框架类图

JarsLink框架的类图如下:

135c3797e899e483b110d92924ebcc0aab977dd7
8481c8f592b7f349aa84a1de5c171db681516edf AbstractModuleRefreshScheduler:入口类,负责定期扫描本地和内存中的模块是否发生变更,如果变更,则更新模块。
8481c8f592b7f349aa84a1de5c171db681516edf ModuleLoader:模块加载引擎,负责模块加载。
8481c8f592b7f349aa84a1de5c171db681516edf ModuleManager:模块管理者,负责在运行时注册,卸载,查找模块和执行Action。
8481c8f592b7f349aa84a1de5c171db681516edf Module:模块,一个模块有多个Action。
8481c8f592b7f349aa84a1de5c171db681516edf Action:模块里的执行者。

如何使用?

1:引入POM

JarsLink Maven Repo

abc9950ab261e800f09a282453d59c1d8a0eb0c4

JarsLink依赖的POM也需要引入

55507de14bce608f2d02c118c47b367b4b111927

2:引入jarslink BEAN

在系统中引入以下两个BEAN。

2b0df9366927ef60ecceffc4d58437acdf0972dd

3:集成JarsLink API

使用JarsLink API非常简单,只需要继承AbstractModuleRefreshScheduler,并提供模块的配置信息,代码如下:

1d30ccc76f16548a563a9be959a282045a5d394c

这个调度器在bean初始化的时候会启动一个调度任务,每分钟刷新一次模块,如果模块的版本号发生变更则会更新模块。实现这个方法时,必须把模块(jar包)下载到机器本地,模块的配置信息说明如下:

8481c8f592b7f349aa84a1de5c171db681516edf name:全局唯一,建议使用英文,忽略大小写。
8481c8f592b7f349aa84a1de5c171db681516edf enabled:当前模块是否可用,默认可用,卸载模块时可以设置成false。
8481c8f592b7f349aa84a1de5c171db681516edf version:模块的版本,如果版本号和之前加载的不一致,框架则会重新加载模块。
8481c8f592b7f349aa84a1de5c171db681516edf Properties:spring属性配置文件。
8481c8f592b7f349aa84a1de5c171db681516edf moduleUrl:模块的本地存放地址。
8481c8f592b7f349aa84a1de5c171db681516edf overridePackages:需要突破双亲委派的包名,一般不推荐使用,范围越小越好,如com.alipay.XX。

把ModuleRefreshSchedulerImpl类注册成Spring的bean。

b5d16d52b00a73e30097dc5070e49900e90d5056

JarsLink API 暂时不提供模块可视化管理能力,所以需要使用其他系统来管理和发布模块。目前可以通过com.alipay. jarslink.api.ModuleManager#getModules获取运行时所有模块的信息。

你也可以使用API来加载并注册模块,详细使用方式可以参考ModuleManagerTest,代码如下。

25e1e61ed1a83e628912926764eb6892589b322c

3:开发模块

在模块中只需要实现并开发Action,代码如下:

0db6e3e4d43cf17fa1d31858ded4fe4e01c9655d

5:调用接口

开发者需要利用JarsLink API把请求转发给模块,先根据模块名查找模块,再根据aciton name查找Action,最后执行Action。

f20b75b4c0fe64dad162fc5ead7e262199626503

其他特性

Spring配置

通过moduleConfig的Properties属性可以设置Spring bean变量的配置信息。

02f6615a26da674a99c9f3e61596e6ee2920244e

最佳实践

HTTP请求转发

可以把HTTP请求转发给模块处理。

 

消息请求转发

可以把消息转发给模块进行处理。遵循默认大于配置的方式,你可以把TOPIC当做模块名,EventCode当做ActionName来转发请求。

接口说明

JarsLink框架最重要的两个接口是ModuleManager和ModuleLoader。

ModuleManager接口

ModuleManager负责注册,卸载,查找模块和执行Action。

15140a1db7cb47966ec09e18d25c838d4313d442

ModuleLoader接口

ModuleLoader只负责加载模块。

b101fac69bcbf50a720ef99dad26a6bf7dee8649

近期,JarsLink会支持多版本加载,并陆续支持模块间调用、资源隔离等特性。我们也希望更多的童鞋参与进来,让JarsLink帮助更多开发者提升效率。


原文发布时间为:2018-03-22

本文作者:清英

本文来自云栖社区合作伙伴“阿里技术”,了解相关信息可以关注“阿里技术”微信公众号

相关文章
|
1月前
|
算法 Java 数据处理
Java集合框架的优缺点
Java集合框架的优缺点
|
1月前
|
运维 监控 Java
推荐一款好用的Java分布式任务调度框架!
推荐一款好用的Java分布式任务调度框架!
168 0
|
1天前
|
设计模式 算法 Java
[设计模式Java实现附plantuml源码~行为型]定义算法的框架——模板方法模式
[设计模式Java实现附plantuml源码~行为型]定义算法的框架——模板方法模式
|
1天前
|
Java Nacos 开发者
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
|
1天前
|
Dubbo Java 应用服务中间件
Java从入门到精通:3.2.2分布式与并发编程——了解分布式系统的基本概念,学习使用Dubbo、Spring Cloud等分布式框架
Java从入门到精通:3.2.2分布式与并发编程——了解分布式系统的基本概念,学习使用Dubbo、Spring Cloud等分布式框架
|
6天前
|
Java Maven 开发工具
《Java 简易速速上手小册》第5章:Java 开发工具和框架(2024 最新版)
《Java 简易速速上手小册》第5章:Java 开发工具和框架(2024 最新版)
26 1
|
10天前
|
Java 大数据 云计算
Spring框架:Java后台开发的核心
【4月更文挑战第15天】Spring框架在Java后台开发中占据核心位置,因其控制反转(IoC)、面向切面编程(AOP)、事务管理等特性提升效率和质量。Spring提供数据访问集成、RESTful Web服务和WebSocket支持。优势包括高效开发、灵活扩展、强大生态圈和广泛应用。应用于企业级应用、微服务架构及云计算大数据场景。掌握Spring对Java开发者至关重要。
|
13天前
|
存储 Java 编译器
Java集合丛林:深入了解集合框架的秘密
Java集合丛林:深入了解集合框架的秘密
15 0
Java集合丛林:深入了解集合框架的秘密
|
16天前
|
存储 Java 数据库连接
java使用mp持久化框架,写入5000个字符,但是VARCHAR(255) 会报错
使用Java的MyBatis Plus框架时,如果尝试将超过VARCHAR(255)限制的字符串(如5000个字符)存入数据库,会抛出异常。解决方法是将列类型改为TEXT。可通过在实体类属性上添加`@TableField(typeHandler = JdbcType.CLOB)`注解,如`private String content;`,将属性映射到CLOB类型列,以存储更长字符串。
9 0
|
17天前
|
存储 Java
java反射——设计框架的灵魂
java反射——设计框架的灵魂