Spring Boot整合PF4J:构建动态插拔的组件化架构

前言

在当今快速迭代的软件开发领域,业务需求的频繁变更对系统架构的灵活性和可扩展性提出了极高要求。传统的单体应用架构在面对功能的不断新增和修改时,往往会陷入代码臃肿、维护困难、扩展性差的困境。组件化开发,为解决这些问题提供了新的思路,通过实现组件的动态插拔,让系统能够更敏捷地响应业务变化。​

1. 背景

在大部分业务场景,微服务拆分不是一个好的选择。服务拆分带来有几方面的挑战:1)成本增加。微服务单独部署需要更多资源,包括服务、负载、网络等;2)应用复杂度增加。微服务需要引入rpc框架,跨服务事务保障,服务链路延长耗时处理等;3)应用维护成本增加。微服务调用链路延长,在排查问题时,如果没有日志链路工具,整个链路追踪下来是非常耗时的,bug修复维护成本大大增加;4)运维成本增加。多服务器夸链路调用,运维成本也会随之增加。

在综合考虑性能和成本的情况,会收缩服务应用,抽象出功能齐全的单体应用。单体架构将所有功能模块打包成一个可执行文件进行部署。这种架构在项目初期,由于功能相对简单,开发和部署都较为便捷。随着业务复杂度增加,一些问题会随之浮现:

  • 通用基础能力之外,需要为不同客户提供定制化功能

  • 代码耦合度越来越高,”屎山“代码堆积,后来者不敢轻易维护,只能重新写逻辑,导致不断增加冗余代码

  • 某些独立功能模块,不随主线迭代发布

  • 某些不需要的功能,需要下线处理掉

  • 紧急Bug或者功能增加,需要紧急替换服务实现

  • 不同团队负责不同业务模块的并行开发

为了应对这些挑战,组件化开发模式应运而生。

2. 组件化开发,实现系统的敏捷响应​

插件模式开发是一种软件架构设计模式,允许应用程序通过动态加载和卸载插件来扩展或定制功能,而无需修改主程序的源代码。这种模式将核心功能与扩展功能分离,使系统具备更高的灵活性、可维护性和可扩展性。

(一)降低维护成本​

在单体架构中,一次小的功能修改可能需要对整个项目进行全面测试,以确保不会影响其他功能。组件化开发后,每个组件都是一个独立的个体。当需要修改某个功能时,只需对对应的组件进行调整和测试,不会影响到其他组件的正常运行,大大降低了维护的复杂度和测试成本。​

(二)加速功能迭代​

传统开发模式下,新功能的添加需要重新构建和部署整个应用,流程繁琐且耗时。采用组件化动态插拔开发,开发人员可以将新功能封装成独立的组件,在运行时动态地将其插入到系统中,无需停机和重新部署整个应用,极大地缩短了新功能的上线周期,使系统能够更快速地响应市场需求。​

(三)提高系统稳定性​

由于组件之间的低耦合性,即使某个组件出现故障,也不会导致整个系统崩溃。其他组件仍然可以正常运行,通过快速定位和修复故障组件,能够有效提高系统的稳定性和可用性。

(四)适配定制化开发

将定制功能抽象到特定的组件中,通过组件化动态插拔组件,可以很好解决客户定制化需求。

3. 组件动态插拔框架选型

在Spring框架下,可选择组件动态插拔框架有:

能力维度OSGiPF4JSpring BrickSpring Plugin CoreSermant
热部署方式Bundle 动态安装/卸载JAR 插件热加载插件包动态安装/卸载配置驱动,需重启应用字节码动态增强
类隔离性✅ 强隔离(独立 ClassLoader)⚠️ 需手动配置隔离✅ 全资源隔离(独立类加载器)❌ 无隔离✅ 宿主应用隔离
Spring 支持度⚠️ 需 Spring DM 适配✅ 原生友好✅ 深度集成(Spring Boot 原生开发)✅ 完全原生⚠️ 部分兼容
通信机制✅ 原生 ServiceTracker⚠️ 需自建事件总线✅ 事件总线 + 主程序路由❌ Bean 直接调用❌ 不支持跨插件通信
适用场景大型企业应用/IDE中小型业务扩展高隔离业务模块/SaaS 定制轻量级静态扩展微服务治理/故障测试
主要限制配置复杂、启动慢隔离性弱、无服务发现需手动管理资源生命周期无热插拔、依赖冲突风险无法新增类/字段

结合自身团队情况以及热插拔需求,我们选择基于PF4J作为Springboot应用的插件框架。关于PL4J的相关介绍,可参考官网

PF4J : PF4JPlugin Framework for Javahttps://pf4j.org/其主要突出点包括:

  • 通过独立类加载器做类隔离,支持运行时热插拔
  • 核心包很小,类加载运行所需内存资源小
  • 与Spring原生支持性好。

4. 方案实现

4.1 搭建运行框架底座

运行框架底座是spirngboot+JPA+内嵌tomcat的web应用,前端资源直接打包成静态文件到fat jar中,后端web控制点有权限拦截器和登录拦截器,数据库支持MySQL和H2内置数据库。

父的pom文件定义:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.test.sf</groupId><artifactId>sf-flow</artifactId><version>1.0-SNAPSHOT</version><packaging>pom</packaging><modules><module>ingress</module><module>app/standardapp</module><module>app/permissionapp</module><module>layer/framework</module><module>layer/datax-spi</module></modules><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.4.1</version><relativePath/> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>21</maven.compiler.source><maven.compiler.target>21</maven.compiler.target><jackson.version>2.17.2</jackson.version><protobuf.version>3.25.5</protobuf.version><grpc.version>1.62.2</grpc.version><aws-sdk-java.version>1.12.725</aws-sdk-java.version><springdoc-openapi-ui.version>2.8.4</springdoc-openapi-ui.version><datax-spi-version>1.0-SNAPSHOT</datax-spi-version><hutool.version>5.8.33</hutool.version></properties><dependencyManagement>...</dependencyManagement><profiles><profile><id>dev</id><properties><environment>dev</environment></properties><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-resources-plugin</artifactId><executions><execution><configuration>
<outputDirectory>${basedir}/target/classes</outputDirectory><resources><resource><directory>src/main/resources</directory><filtering>true</filtering><includes><include>**/application-${environment}.properties</include></includes></resource></resources></configuration></execution></executions></plugin></plugins></build></profile>
</profiles></project>

入口ingress的Main函数实现:

@SpringBootApplication(scanBasePackages = { "com.test.sf"
})
@EnableJpaRepositories(basePackages = {"com.test.sf.layer","com.test.sf.a

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/84007.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/84007.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

剃须效率低?电铸多孔刀网设计如何提升毛发捕捉率

剃须效率低下常源于刀网对毛发的捕捉能力不足——传统冲压刀网因孔型单一、边缘毛刺等问题&#xff0c;导致胡须滑脱或拉扯。而电铸多孔刀网通过精密工艺革新&#xff0c;将毛发捕捉率提升40%以上。其核心优势在于三维立体孔型设计与微米级精度控制&#xff0c;以下是技术解析&…

进一步了解git

1、什么是集中式&#xff1f;什么是分布式&#xff1f; SVN&#xff08;集中式&#xff09; 单一中央仓库&#xff1a;所有代码和历史版本集中存储在中央服务器&#xff0c;用户本地仅保存当前工作副本。 强依赖网络&#xff1a;提交、查看历史等操作需实时连接服务器&#xf…

一、react18+项目初始化

npx create-rect-app 项目名称配置antd design mobile // 安装 npm install --save antd-mobile // 在文件中直接引入使用 import { Button } from antd-mobile <Button></Button>更改webpack配置 // 1.安装必要的包 npm install craco --save-dev // 2.修改pack…

Azure 资源清单

Azure 资源清单 作用前置条件安装PowerShell 7.0验证 Azure资源清单安装配置如果有旧版本&#xff0c;导致新模块安装不上&#xff0c;进行强制安装 PowerShell 登录到 Azure基本命令输出详细信息效果图展示 作用 官方文档&#xff1a;https://github.com/microsoft/ARI?tabr…

S11的含义-信号完整性分析

S11的含义: PCB上的互连结构是线性无源的&#xff0c;在传输信号时激励源只有一个&#xff0c;即驱动器发出的信号。如果正弦信号从端口1进入&#xff0c;根据S11定义&#xff0c;S11表示端口1出来的正弦信号和端口1进入的正弦信号的比值。工程上通常把S11称为回波损耗(Return …

基于OpenCv(开源计算机视觉库)的图像旋转匹配

OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库&#xff0c;具有跨平台特性&#xff0c;广泛应用于工业检测、医疗影像分析、自动驾驶、无人机、机器人视觉等多个领域。 本项目解决了图像模板匹配时的旋转问题。传…

Elasticsearch Open Inference API 新增对 Cohere 的 Rerank 3 模型支持

作者&#xff1a;来自 Elastic Serena Chou 及 Max Hniebergall 了解 Cohere reranking&#xff0c;如何将 Cohere 的 Rerank 3 模型与 Elasticsearch 的 open inference API 一起使用&#xff0c;以及 Elastic 在语义 reranking 方面的路线图。 注&#xff1a;原文在 2024 年 …

九日集训第六天

目录 两个数对之间最大的乘积差 三角形的最大周长 数组拆分 救生艇 摆动排序|| 分发饼干 最少操作使数组递增 使数组唯一的最小增量 有效三角形的个数 两个数对之间最大的乘积差 class Solution { public:int maxProductDifference(vector<int>& nums) {so…

【软件工程】Waitress + Nginx 部署 Python Web 服务

下面是完整的 Windows 系统部署方案,使用 Waitress 作为 WSGI 服务器运行 Python 后端,Nginx 作为反向代理同时提供前端服务: 项目结构 text 复制 下载 myapp/ ├── backend/ # Python后端 │ ├── app.py # Flask应用入口 │ ├──…

JS数据类型检测方法总结

在 JavaScript 中&#xff0c;数据类型检测是开发中的常见需求。以下是主要检测方法及其优缺点&#xff1a; 1. typeof 操作符 最基础的检测方式&#xff0c;返回类型字符串&#xff1a; typeof 42; // "number" typeof "hello"; // &qu…

AEO:从搜索引擎到答案引擎,AI时代搜索优化的新战场

在 ChatGPT、DeepSeek、Google SGE 等生成式AI崛起的时代&#xff0c;搜索正在经历一场根本性变革&#xff1a; 过去&#xff1a;搜索引擎优化&#xff08;SEO&#xff09; 现在&#xff1a;答案引擎优化&#xff08;AEO&#xff09; 当搜索结果开始由AI直接生成“答案”而非…

搭建Node.js服务器

1.基础HTTP服务器: 添加了路由处理添加了404错误处理添加了服务器错误监听 2.静态资源服务器: 使用异步文件操作支持目录自动索引(默认加载 index.html)自动检测文件类型并设置正确Content-Type更完善的错误处理 3.处理GET请求参数 提供了一个HTML表单用于测试使用url模块…

Linux grep 命令

grep 是 Linux/Unix 系统中用于文本搜索的强大工具&#xff0c;支持基于正则表达式的模式匹配。以下是其详细用法及实际应用示例&#xff1a; 基本语法 grep [选项] 模式 [文件...]模式&#xff1a;要搜索的字符串或正则表达式。文件&#xff1a;可以是单个文件或多个文件&…

oracle 11g通过rman做备份和还原

ORACLE RMAN增量备份完整恢复测试 1.创建测试环境: 1.1.创建测试表空间 SQL> create tablespace tablespace1 datafile ‘/data/u01/app/oracle/oradata/orcl/tablespace1.dbf’ size 10m; SQL> 1.2.创建测试用户并指定为默认表空间: SQL> create user user1 iden…

为什么TCP有粘包问题,而UDP没有

TCP粘包问题源于其面向字节流的设计&#xff0c;而UDP无此问题因其基于数据报的传输机制。 &#x1f50d; 一、TCP粘包问题的原因 字节流传输特性 TCP将数据视为连续的字节流&#xff0c;而非独立的消息包。发送端多次写入的小数据可能被合并为一个TCP段发送&#xff1b;接收端…

ELM:Embodied Understanding of Driving Scenarios

1. ELM 的创新点与核心思路 ELM 的核心在于 “具身理解”(Embodied Understanding),即通过常识与环境交互并进行推理,这一理念适用于自动驾驶车辆、机器人和无人机等多种应用场景。具身智能体(Embodied Agent)需具备四大核心能力:首先,它能够描述周围环境,对交通物体的…

实景VR知识科普

实景VR的定义与技术特点 实景VR&#xff0c;即基于真实场景的虚拟现实技术&#xff0c;是通过计算机生成的三维环境&#xff0c;旨在模拟并再现真实世界场景。用户佩戴VR设备&#xff08;如VR头盔、手柄等&#xff09;后&#xff0c;能够沉浸在一个高度仿真的虚拟环境中&#…

CppCon 2016 学习:ITERATOR HAIKU

这组幻灯片讲解了 C 中**范围&#xff08;Ranges&#xff09;和迭代器&#xff08;Iterators&#xff09;**的核心概念&#xff0c;特别是 C14 标准定义的五种迭代器类别&#xff0c;以及范围的基本使用方式。我帮你理个思路&#xff1a; 1. RANGE-SEQUENCE: 元素范围&#xf…

开源飞控fmt软件在环仿真环境搭建

tags: 飞控 fmt开发环境搭建 fmt是国产开源飞控&#xff0c;特点是支持基于模型设计&#xff08;基于simulink仿真&#xff09;&#xff0c;源码结构目录较清晰&#xff0c;项目体积较小。 此项目操作系统选择的是国产实时操作系统rt-thread&#xff0c;也是开源项目。&#…

如何通过AI测试平台实现自动化缺陷检测和优化

在数字化转型加速的今天&#xff0c;软件质量保证已成为企业竞争力的关键要素之一。传统的手工测试方法面临着效率低下、成本高昂和覆盖面有限等挑战&#xff0c;而AI技术的融入为软件测试领域带来了革命性的变化。本文将深入探讨如何构建一个完整的AI测试平台&#xff0c;实现…