【lattice】 lattice-dynamic-loading 深度源码分析

简介: lattice-dynamic-loading 模块实现插件热加载与运行时扩展,通过独立类加载器保障隔离性,集成 Spring 生态,支持动态注册 Bean 与 MVC。基于策略模式、门面模式和 SPI 机制,实现高扩展性、可维护性与热部署能力,提升系统敏捷性。(239字)

SITUATION(背景情境)

1.1 业务场景定位

在 Lattice 框架的插件化架构中,lattice-dynamic-loading 模块解决了以下核心问题:

插件热加载:无需重启应用即可加载新业务插件

运行时扩展:支持业务方在运行时动态添加/删除业务逻辑

隔离性保障:每个插件使用独立的类加载器,避免类冲突

Spring 生态集成:将插件中的 Bean 和 MVC Controller 动态注册到 Spring 容器


1.2 技术依赖分析

依赖



作用
lattice-model

提供核心注解和模型定义

lattice-runtime 提供运行时注册和执行能力
commons-configuration2 读取配置文件
commons-io 文件操作工具
spring-boot-starter-web Spring MVC 动态注册

二、TASK(设计目标)

lattice-dynamic-loading
├── 插件生命周期管理
│   ├── 插件安装(Install)
│   └── 插件卸载(Uninstall)
├── 类加载隔离
│   ├── 自定义 ClassLoader
│   └── 类加载策略
├── 资源注册
│   ├── Business 注册
│   ├── Product 注册
│   └── Spring Bean 注册
└── 配置管理
    ├── 插件目录配置
    └── 运行时属性管理

设计原则遵循

单一职责:每个 Installer/Uninstaller 只负责一种资源类型

开闭原则:通过接口扩展,可轻松添加新的安装器

依赖倒置:依赖抽象的 LatticeInstaller 接口

里氏替换:所有 Installer 实现可互相替换


三、ACTION(实现架构)

3.1 目录结构分析

lattice-dynamic-loading/
├── 📦 classloader/              【类加载层】
│   ├── LatticeClassLoader.java              // 自定义类加载器
│   └── LatticeDynamicClassLoaderBuilder.java // SPI 实现,提供类加载器
├── 🔧 installer/                【安装层】
│   ├── LatticeInstaller.java               // 安装器接口
│   ├── BusinessInstaller.java              // Business 安装器
│   ├── ProductInstaller.java               // Product 安装器
│   ├── SpringInstaller.java                // Spring Bean/MVC 安装器
│   └── InstallResult.java                  // 安装结果封装
├── 🗑️ destroy/                  【卸载层】
│   ├── LatticeUninstaller.java             // 卸载器接口
│   ├── BusinessUninstaller.java            // Business 卸载器
│   ├── ProductUninstaller.java             // Product 卸载器
│   ├── SpringUninstaller.java              // Spring Bean/MVC 卸载器
│   └── DestroyResult.java                  // 卸载结果封装
├── 📋 model/                    【模型层】
│   ├── PluginFileInfo.java                 // 插件文件元信息
│   └── SpringBeanInfo.java                 // Spring Bean 信息
├── ⚙️ config/                   【配置层】
│   └── LatticeDynamicConfig.java           // 动态加载配置
├── 🎛️ properties/               【属性层】
│   ├── LatticeDynamicProperties.java       // 插件目录配置
│   └── DynamicApplicationProperties.java   // 应用属性读取
├── 🛠️ utils/                    【工具层】
│   ├── DynamicUtils.java                   // 动态加载工具
│   └── SpringUtils.java                    // Spring Bean 操作工具
└── 🎯 LatticeDynamic.java       【核心门面】
    // 插件管理的统一入口

3.2 核心流程设计(执行链路)

3.2.1 插件安装流程(STAR 分析)

Situation:用户上传一个插件 JAR 文件

Task:将 JAR 中的 Business/Product/Spring Bean 注册到系统

Action:installPlugin() 方法执行

// 执行链路分析
installPlugin(originFile)
1. copyAndCreatePluginFile()        // 文件复制到插件目录
2. new LatticeClassLoader()         // 创建隔离的类加载器
3. BusinessInstaller.install()      // 注册 Business 和 Realization
4. ProductInstaller.install()       // 注册 Product
5. SpringInstaller.install()        // 注册 Spring Bean 和 MVC
6. Lattice.getInstance().reload()   // 重新加载缓存

Result:插件成功注册,业务逻辑立即生效

3.2.2 插件卸载流程

Situation:需要移除某个插件

Task:清理所有注册的资源

Action:uninstallPlugin() 方法执行

// 执行链路分析
uninstallPlugin(id)
1. 查找 PluginFileInfo              // 根据 MD5 ID 查找插件
2. BusinessUninstaller.uninstall()  // 清除 Business 缓存
3. ProductUninstaller.uninstall()   // 清除 Product 缓存
4. SpringUninstaller.uninstall()    // 注销 Spring Bean 和 MVC
5. file.delete()                    // 删除插件文件
3.3 关键设计模式
3.3.1 策略模式(Installer/Uninstaller)

// 接口定义
interface LatticeInstaller {
    InstallResult install(LatticeClassLoader classLoader, PluginFileInfo fileInfo);
}

// 具体策略
- BusinessInstaller   // 处理业务逻辑注册
- ProductInstaller    // 处理产品注册
- SpringInstaller     // 处理 Spring 生态注册

优势:

✅ 易于扩展新的资源类型

✅ 每个 Installer 职责单一

✅ 可独立测试和维护


3.3.2 门面模式(LatticeDynamic)

[LatticeDynamic](file:///Volumes/xuan-pan/lattice/lattice-tools/lattice-dynamic-loading/src/main/java/org/hiforce/lattice/dynamic/LatticeDynamic.java#L34-L203) 提供统一的插件管理接口:


public class LatticeDynamic {
    // 对外暴露的简单接口
    public void installPlugin(PluginFileInfo file)
    public void uninstallPlugin(String id)
    
    // 内部协调多个 Installer/Uninstaller
    private List<LatticeInstaller> installers = Lists.newArrayList(
        new BusinessInstaller(),
        new ProductInstaller(),
        new SpringInstaller()
    );
}

优势:

✅ 隐藏内部复杂性

✅ 提供统一的操作入口

✅ 便于集中管理插件状态


3.3.3 SPI 机制(CustomClassLoaderSpi)

LatticeDynamicClassLoaderBuilder 通过 @AutoService 实现 SPI:

✅ 自动被 Lattice 框架发现

✅ 将插件 ClassLoader 注入到框架核心

✅ 实现插件类的运行时加载

3.4 核心技术实现剖析

3.4.1 插件隔离机制

问题:如何防止插件之间的类冲突?

解决方案:PluginFileInfo 使用 MD5 唯一标识

public class PluginFileInfo {
    private String id;  // 文件内容的 MD5 值
    
    private void buildMD5Value() {
        MessageDigest digest = MessageDigest.getInstance("MD5");
        byte[] bytes = digest.digest(FileUtils.readFileToByteArray(file));
        // 转换为 16 进制字符串作为唯一 ID
    }
}

优势:

✅ 基于内容的唯一性,防止重复安装

✅ 可通过 ID 精确定位插件

✅ 支持版本升级(内容变化则 ID 变化)


3.4.2 Spring Bean 动态注册

挑战:如何将插件中的 @Service 和 @RestController 注册到运行中的 Spring 容器?

实现:SpringInstaller 的精妙设计


// 1. 扫描插件中带有 Spring 注解的类
List<Class<?>> classList = fileInfo.getJarFile().stream()
    .filter(p -> p.endsWith(".class"))
    .map(className -> classLoader.loadClass(className))
    .filter(this::hasSpringAnnotation)
    .collect(Collectors.toList());

// 2. 动态注册 Bean
for (Class<?> clazz : classList) {
    Object bean = SpringUtils.registerBean(clazz.getSimpleName(), clazz);
}

// 3. 动态注册 MVC 映射
RequestMappingHandlerMapping mapping = ...;
for (Method method : methods) {
    RequestMappingInfo info = buildMappingInfo(method);
    mapping.registerMapping(info, bean, method);
}

关键点:

✅ 通过反射扫描 JAR 包内的所有类

✅ 使用 BeanDefinitionRegistry 动态注册

✅ 手动注册 RequestMapping 到 Spring MVC

✅ 支持自动装配(autowireBean)


3.4.3 资源清理机制

问题:卸载插件时如何彻底清理?

方案:SpringUninstaller 精准清理


public DestroyResult uninstall(...) {
    // 1. 清理 MVC 映射
    beans.stream()
        .filter(SpringBeanInfo::isMvc)
        .forEach(info -> {
            RequestMappingHandlerMapping mapping = ...;
            info.getMappingInfos().forEach(mapping::unregisterMapping);
        });
    
    // 2. 清理 Spring Bean
    beans.forEach(p -> SpringUtils.removeBean(p.getBeanName()));
    
    return DestroyResult.success();
}

保障措施:

✅ 记录所有注册的 Bean 和 Mapping

✅ 卸载时逆向操作

✅ 防止内存泄漏

四、RESULT(设计成果)

4.1 架构优势


维度

实现效果

技术保障

可扩展性

新增资源类型只需实现 Installer 接口

策略模式 + 接口编程

隔离性

插件间类互不干扰

独立 ClassLoader

可靠性

安装失败自动回滚

Try-with-resources + 异常处理

可观测性

详细的日志输出

SLF4J 日志集成

热部署

零停机更新业务逻辑

动态注册 + 缓存刷新

4.2 性能考量

类加载优化:

使用 try-with-resources 自动关闭 ClassLoader

避免类加载器泄漏

并发安全:

installPlugin() 和 uninstallPlugin() 使用 synchronized

currentFiles 使用 ConcurrentHashSet

资源管理:

插件卸载时删除物理文件

清理所有注册的 Bean 和 Mapping

4.3 潜在风险与改进建议

⚠️ 风险点

类加载器内存泄漏:

问题:如果插件类被系统持有引用,ClassLoader 无法回收

建议:增加引用检测和强制清理机制

Spring Bean 冲突:

问题:不同插件可能注册同名 Bean

建议:Bean 名称加插件前缀

并发安装冲突:

问题:多个插件同时安装可能冲突

建议:使用队列顺序处理


五、总结:设计哲学

lattice-dynamic-loading 的设计体现了以下哲学:

职责分离:安装、卸载、类加载各司其职

插件化思维:连 Spring 集成都视为可选的 Installer

防御性编程:大量的异常处理和日志记录

运行时增强:不改变框架核心,通过插件扩展能力

核心价值:让 Lattice 框架从"编译时固定"进化为"运行时可变",实现真正的业务敏捷性。

目录
相关文章
|
8月前
|
设计模式 Java
【TMF】源码分析 1.0 LatticeClassLoader
LatticeClassLoader扩展Java双亲委派模型,支持多自定义类加载器的委托加载。类加载失败后依次尝试自定义加载器,实现插件化容错;资源获取优先父加载器,支持单资源查找与多资源聚合,适用于插件系统、多租户隔离及SPI扩展,保障业务隔离与灵活扩展。
304 1
|
8月前
|
Dubbo Java 测试技术
【Lattice】设计原理
Lattice 是一个轻量级业务扩展调用框架,通过模块化架构实现复杂业务定制的高效管理。支持动态发现、加载与执行扩展,提供清晰的分层设计,集成 Spring、Dubbo 等主流技术,助力企业应用灵活扩展。
814 0
|
8月前
|
运维 监控 供应链
Alibaba交易平台TMF2.0介绍
2017双11交易峰值达32.5万笔/秒,面对高并发与复杂业务需求,阿里推出TMF2.0框架,通过业务与平台分离、全链路可视化、配置化发布等创新,实现需求开发周期缩短至12天,支撑多业务快速试错与复用,构建可配置、可监控、可运维的电商技术新体系。
1118 5
Alibaba交易平台TMF2.0介绍
|
10月前
|
人工智能 缓存 安全
阿里云发布《AI 原生应用架构白皮书》
阿里云联合阿里巴巴爱橙科技,共同发布《AI 原生应用架构白皮书》,围绕 AI 原生应用的 DevOps 全生命周期,从架构设计、技术选型、工程实践到运维优化,对概念和重难点进行系统的拆解,并尝试提供一些解题思路。白皮书覆盖 AI 原生应用的 11 大关键要素,获得 15 位业界专家联名推荐,来自 40 多位一线工程师实践心的,全书合计超 20w 字,分为 11 章。
4507 81
|
6月前
|
数据采集 人工智能 Java
核心目标:构建Java全流程AI Agent
在AI深度赋能企业背景下,依托JBoltAI框架,打造贯穿业务全链路的全流程AI Agent。突破传统自动化局限,实现跨模块协同、多系统融合与自适应迭代,推动Java生态智能化升级。
689 5
|
8月前
|
存储 Java 编译器
【TMF】 解析器底层原理分析
该注解处理器在编译期自动扫描特定注解(如@Extension、@Business),收集标记的类或方法,生成SPI配置文件,实现服务接口与实现类的自动注册,提升开发效率与准确性。
305 2
|
9月前
|
存储 消息中间件 Kafka
Confluent 首席架构师万字剖析 Apache Fluss(三):湖流一体
原文:https://jack-vanlightly.com/blog/2025/9/2/understanding-apache-fluss 作者:Jack Vanlightly 翻译:Wayne Wang@腾讯 译注:Jack Vanlightly 是一位专注于数据系统底层架构的知名技术博主,他的文章以篇幅长、细节丰富而闻名。目前 Jack 就职于 Confluent,担任首席技术架构师,因此这篇 Fluss 深度分析文章,具备一定的客观参考意义。译文拆成了三篇文章,本文是第二篇。
918 25
Confluent 首席架构师万字剖析 Apache Fluss(三):湖流一体

热门文章

最新文章