当前位置: 首页 > news >正文

插件框架PF4J-从理论到实践

PF4J:Plugin Framework for Java

目录

是什么?

不是什么?

特点

组件

主要类

流程概述

spring-pf4j

思考

功能模块化


我对pf4j的封装和使用demo

GitHub - chlInGithub/pf4jDemo: pf4j demo 

是什么?

开源轻量级的插件框架。通过插件形式对系统功能进行个性化扩展。插件需要实现扩展点,扩展点由系统进行定义。

不是什么?

功能模块化加载框架。虽然介绍中描述pf4j可以将庞大的系统转化为模块系统,但依据我的实践来看,仅仅依赖pf4j只能动态加载扩展,无法动态加载完整的功能模块。

特点

  • 开源轻量级的插件框架
  • 简单的标记扩展点,使用interface ExtensionPoint即可将接口和抽象类定义为扩展点
  • 简单的标记扩展,使用@Extension即可定义一个扩展

组件

插件  等同于 由 扩展点、扩展、生命周期行为 构成的一个集合。 

Plugin所有插件的基类。每一个插件均由单独的classloader进行加载,避免冲突。
PluginManager对插件进行切面化管理,如loading, starting, stopping。已提供3中实现,JarPluginManager, ZipPluginManager, DefaultPluginManager(jar_zip)。也可自行实现个性化pluginManager,需要实现AbstractPluginManager。
PluginLoader加载插件需要的所有信息,如class
ExtensionPoint扩展点
Extension扩展,即扩展点的实现

主要类 

PluginManagerpf4j通过PluginManager向外提供plugin管理能力,如生命周期控制、获取扩展实例
PluginWrapperplugin的包装类
ManifestPluginDescriptorFinder从(支持jar\zip\目录)manifest文件读取插件信息,如Plugin-Id(用于避免重复load)、Plugin-Version、Plugin-Class
PluginLoader

用于load plugin需要的所有信息,每个pluginPath对应一个pluginLoader,为每个plugin提供独立的classloader。

如JarPluginLoader

PluginClassLoader自定义的classLoader,修改了loadClass的逻辑。每个plugin对应一个PluginClassLoader实例
PluginState插件生命周期期间的各种状态
DependencyResolver插件间依赖关系分解器。一系列插件之间构建依赖图,唯一入口resolve可以返回依赖分解结果,如插件之间是否存在循环依赖、能否找到依赖的插件、插件依赖版本是否正确等。
LegacyExtensionFinder读取plugin包中META-INF/extensions.idx文件,获取扩展信息和实例。

生命周期概述

加载插件过程MF文件中插件描述-->插件独立classLoader-->插件间依赖解析-->插件已解析状态
开始插件过程加载Plugin实现并生成实例-->调用Plugin.start()-->插件已开始状态
获取某个扩展点实现类的实例
停止插件插件状态变为停止
卸载插件从集合中清除,关闭classLoader

spring-pf4j

将扩展注册为spring ioc bean

思考

如何支持租户场景

pf4j非线程安全,允许不同租户维护各自插件的场景,需要在pf4j基础上再包裹一层,一方面增加线程安全,一方面维护租户与插件、扩展的关系。

需要以一种路径规范存放插件jar,如下图:

如何支持插件依赖的jar

  • 方式1:系统列举出支持的jar集合,插件依赖其中的jar。在demo中已体现该场景,插件正常运行。

如图为插件的pom依赖,插件jar中不包含依赖的任何jars。

插件jar放到上图的租户路径下,在系统中运行Pf4jTest.main,插件扩展运行正常。因为系统的classpath中包含common-lang jar,所以classloader可以找到common-lang中class。

扩展运行结果如下,可以清晰看出,两个插件的classloader是独立的。

  • 方式2:插件jar内部包含依赖的jars
    • 方式2.1:jdk的classloader不支持嵌套jar,需参考spring LaunchedURLClassLoader或JarClassLoader(http://www.jdotsoft.com/JarClassLoader.php)。在不改变pf4j源码情况下,无法实现该方案,因为pf4j使用URLClassLoader。
    • 方式2.2:解压插件jar-->pf4j加载插件jar-->修改生成的classloader的扫描范围,添加依赖jars路径-->启动插件jar
  • 方式3:系统根据插件jar的(maven)依赖去下载依赖的jar

功能模块化

基本能力:系统功能进行模块划分,模块可动态加载和卸载,模块独立且隔离,模块间资源不产生冲突。
设计思路:独立的classloader(修改加载class的顺序,自有范围-->双亲委派)、springcontext、生命周期管理
 

相关文章:

插件框架PF4J-从理论到实践

PF4J:Plugin Framework for Java 目录 是什么? 不是什么? 特点 组件 主要类 流程概述 spring-pf4j 思考 功能模块化 我对pf4j的封装和使用demo GitHub - chlInGithub/pf4jDemo: pf4j demo 是什么? 开源轻量级的插件框架。通过插件…...

怎么将pdf文件免费转为扫描件

推荐两个工具,也算是给自己记一下 1、手机:扫描全能王APP 太好使了,可以直接拍照并转换为扫描件 不开会员的话会出现水印,因为我都是自己用或者交作业就没开 支持读取相册,一次一张、多张都可以 如果不想要水印也…...

vue+nodejs校园二手物品交易市场网站_xa1i4

。为满足如今日益复杂的管理需求,各类管理系统程序也在不断改进。本课题所设计的校园二手交易市场,使用vue框架,Mysql数据库、nodejs语言进行开发,它的优点代码不能从浏览器查看,保密性非常好,比其他的管理…...

Barra模型因子的构建及应用系列六之Book-to-Price因子

一、摘要 在前期的Barra模型系列文章中,我们构建了Size因子、Beta因子、Momentum因子、Residual Volatility因子和NonLinear Size因子,并分别创建了对应的单因子策略,其中Size因子和NonLinear Siz因子具有很强的收益能力。本节文章将在该系列…...

【c语言习题】使用链表解决约瑟夫问题

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c语言系列专栏&#xff1a;c语言之路重点知识整合 &#x…...

JVM之类的初始化与类加载机制

类的初始化 clinit 初始化阶段就是执行类构造器方法clinit的过程。此方法不需定义&#xff0c;是javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来。构造器方法中指令按语句在源文件中出现的顺序执行。clinit不同于类的构造器。(关联&#xff1a;…...

面试专题:java 多线程(1)----synchronized关键字相关问答

在java 多线程 面试中最多问题1.悲观锁和乐观锁&#xff1b;2.synchronized和lock的区别&#xff1b;3.可重入锁和非可重入锁的区别&#xff1b;4.多线程是解决什么问题的&#xff1b;5.线程池解决什么问题的&#xff1b;6.线程池原理&#xff1b;7.线程池使用注意事项&#xf…...

VMware SD-WAN 5.2 发布 - 软件定义的 WAN

VMware SD-WAN 5.2 发布 - 软件定义的 WAN SD-WAN 解决方案的领导者 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-sd-wan-5/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org 产品概述 软件定义的 WAN (SD-WAN)…...

Oracle+11g+RAC+PSU_EAM(2)

2.15 解压安装介质 在获取开篇1.2节中提到的安装介质如下&#xff1a; [rootebsrac1 ~]# ls -l -rw-r–r– 1 root root 1358454646 Apr 20 16:22 p13390677_112040_Linux-x86-64_1of7.zip -rw-r–r– 1 root root 1142195302 Apr 20 16:29 p13390677_112040_Linux-x86-64_…...

智能出行 驱动未来|2023 开放原子全球开源峰会 CARSMOS 开源智能出行生态年会即将启幕

由开放原子开源基金会主办&#xff0c;元遨 / CARSMOS 开源智能出行项目组协办&#xff0c;深信科创、Futurewei Technologies、Open Motors、北极雄芯等单位共同承办的 2023 开放原子全球开源峰会 “CARSMOS 开源智能出行生态年会” 将于 6 月 12 日在北京经开区北人亦创国际会…...

Linux:centos:周期性计划任务管理《crontab》

crontab常用基础属性 -e 编辑计划任务 -l 查看计划任务 -r 删除计划任务 -u 指定用户的计划任务 首先创建一个名为test的用户名 crontab时间规定 格式&#xff1a;分钟 小时 日期 月份 星期 命令 分钟-- 0-59整数 小时 -- 0-23整数 日期 -- 1--31 整数 月份 -- 1-12 整数 星期…...

克拉默法则证明(Cramer‘s Rule)

若 n 个方程 n 个未知量构成的非齐次线性方程组&#xff1a; { a 11 x 1 a 12 x 2 . . . a 1 n x n b 1 a 21 x 1 a 22 x 2 . . . a 2 n x n b 2 . . . . . . a n 1 x 1 a n 2 x 2 . . . a n n x n b n \begin{equation*} \begin{cases} a_{11}x_{1} a_ {12}x_{2}…...

【接口防刷】处理方案

【接口防刷】 欢迎使用【接口防刷】常见的处理方案访问次数和频率限制验证码校验登录校验机制数据交互加密异常监测机制附录 欢迎使用【接口防刷】常见的处理方案 接口防刷处理方案是指为了防止恶意攻击或非法数据采集&#xff0c;采取一系列技术措施来保护接口数据的安全和完…...

安装Linux-SUSE操作系统

文章目录 一、安装Linux-SUSE系统1、环境准备2、SUSE 镜像的下载2.1、下载企业服务器2.2、ARM和桌面的ISO 3、安装SUSE4、配置本地 yum 源5、SUSE常用安装命令6、在 SUSE系统上安装mysql数据库步骤&#xff1a;7、破解SUSE系统root密码 一、安装Linux-SUSE系统 1、环境准备 操…...

二、机器人的结构设计

1 、螺丝连接的坚固性 坚固性是机器人能顺利完成指定任务的一个重要条件&#xff0c;无论我们程序设计的如何完美&#xff0c; 如果不能保证机器人具有坚固性和稳定性&#xff0c;就无法保证任务的顺利完成&#xff0c;机器人在运行时如 果发生散架和分裂都会影响其功能的实现…...

UITableView学习笔记

看TableView的资料其实已经蛮久了&#xff0c;一直想写点儿东西&#xff0c;却总是因为各种原因拖延&#xff0c;今天晚上有时间静下心来记录一些最近学习的TableView的知识。下面进入正题&#xff0c;UITableView堪称UIKit里面最复杂的一个控件了&#xff0c;使用起来不算难&a…...

Nginx反向代理与负载均衡

简介 Nginx 是一款高性能、轻量级的 Web 服务器软件&#xff0c;常用于反向代理和负载均衡。以下是 Nginx 反向代理和负载均衡的基本原理和实现方式 1、反向代理 当客户端请求访问一个 Web 服务器时&#xff0c;首先会发送请求到 Nginx&#xff0c;然后 Nginx 将请求转…...

Delaunay三角剖分学习笔记

文章目录 Delaunay三角剖分学习笔记1 Voronoi \text{Voronoi} Voronoi图1.1 定义与性质 2 三角剖分2.1 定义与性质2.2 质量(quality)评定标准 3 Delaunay三角剖分3.1 定义3.2 准则与性质 4 Delaunay三角剖分算法4.1 Bowyer-Watson算法4.1.1 算法步骤&#xff1a;4.1.2 算法伪代…...

@Resource和@Autowired的区别

1.相同点 Resource和Autowired这两个注解的作用都是在Spring生态里面去实现Bean的依赖注入 2.不同点 2.1 Autowired 首先&#xff0c;Autowired是Spring里面提供的一个注解&#xff0c;默认是根据类型来实现Bean的依赖注入。 Autowired注解里面有一个required属性默认值是t…...

linux达梦数据库的安装与卸载

一、安装 创建dmdba用户及用户组 创建安装目录&#xff1a; mkdir -p /dm8 创建组 &#xff1a;groupadd dinstall 创建用户 &#xff1a;useradd -g dinstall dmdba 设置密码 &#xff1a;passwd dmdba 创建文件夹&#xff1a;mkdir /dmdata 更改安装目录所有者&#xff1a; c…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...

git: early EOF

macOS报错&#xff1a; Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...

GraphQL 实战篇:Apollo Client 配置与缓存

GraphQL 实战篇&#xff1a;Apollo Client 配置与缓存 上一篇&#xff1a;GraphQL 入门篇&#xff1a;基础查询语法 依旧和上一篇的笔记一样&#xff0c;主实操&#xff0c;没啥过多的细节讲解&#xff0c;代码具体在&#xff1a; https://github.com/GoldenaArcher/graphql…...

篇章二 论坛系统——系统设计

目录 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 1. 数据库设计 1.1 数据库名: forum db 1.2 表的设计 1.3 编写SQL 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 通过需求分析获得概念类并结合业务实现过程中的技术需要&#x…...

JDK 17 序列化是怎么回事

如何序列化&#xff1f;其实很简单&#xff0c;就是根据每个类型&#xff0c;用工厂类调用。逐个完成。 没什么漂亮的代码&#xff0c;只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...