PF4J+SpringBoot
plugin-common
pom.xml相关配置
<groupId>pub.qingyun</groupId>
<artifactId>plugin-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<description>插件配置类</description><dependency><groupId>org.pf4j</groupId><artifactId>pf4j</artifactId><version>3.12.0</version>
</dependency><!--插件打包时使用的Maven插件,插件ID:Plugin-Id,使用mvn clean package 打出*jar-with-dependencies.jar的插件包-->
<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><configuration><archive><manifest><addClasspath>true</addClasspath></manifest><manifestEntries><Plugin-Id>common-impl</Plugin-Id><Plugin-Version>0.0.1</Plugin-Version></manifestEntries></archive><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs></configuration><executions><execution><id>make-assembly</id><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin></plugins>
</build>
插件服务接口
pub.qingyun.service.IExtensionHandler
public interface IExtensionHandler extends Runnable, ExtensionPoint {String execute(String param);
}
实现类
import org.pf4j.Extension;
import pub.qingyun.service.IExtensionHandler;@Extension
public class TestExtensionHandler implements IExtensionHandler {@Overridepublic void run() {System.out.println("TestExtensionHandler run...");}@Overridepublic String execute(String param) {System.out.println("TestExtensionHandler.execute...param=" + param);return param;}
}
plugin-spring-boot
pom.xml相关配置
<groupId>pub.qingyun</groupId>
<artifactId>plugin-spring-boot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>plugin-spring-boot</name>
<description>plugin-spring-boot</description><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.6.13</spring-boot.version>
</properties>
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>pub.qingyun</groupId><artifactId>plugin-common</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>...
</dependencies>
<dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement>
spring-boot
@Configuration
public class PluginConfig {// 插件目录,对应插件jar包/zip@Value("${pf4j.pluginPath}")private String pf4jPluginPath;@Beanpublic PluginManager initPluginManager() {Path pluginPath = Paths.get(pf4jPluginPath);PluginManager pluginManager = new JarPluginManager(pluginPath);//加载所有插件pluginManager.loadPlugins();//开启所有插件pluginManager.startPlugins();//启动指定插件
// pluginManager.startPlugin("demo-plugin");//卸载插件
// pluginManager.unloadPlugin("demo-plugin");return pluginManager;}
}
控制层实现
package pub.qingyun.controller;import lombok.extern.slf4j.Slf4j;
import org.pf4j.PluginManager;
import org.pf4j.PluginState;
import org.pf4j.PluginWrapper;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import pub.qingyun.service.impl.TestExtensionHandler;import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;/*** @author CQY* @version 1.0* @date 2024/7/17 14:19**/
@Slf4j
@RestController
public class PluginController {@Resourceprivate PluginManager pluginManager;/*** 打印所有插件信息** @return List<Map < String, Object>>*/@GetMapping(value = "/printAllPlugin")public ResponseEntity<List<Map<String, Object>>> printAllPlugin() {List<PluginWrapper> plugins = pluginManager.getPlugins();List<Map<String, Object>> collect = plugins.stream().map((item) -> {Map<String, Object> map = new HashMap<>();map.put("pluginId", item.getPluginId());map.put("pluginDescription", item.getDescriptor());map.put("pluginPath", item.getPluginPath());map.put("pluginState", item.getPluginState());map.put("pluginClassLoader", item.getPluginClassLoader());return map;}).collect(Collectors.toList());return ResponseEntity.ok(collect);}/*** 启动插件** @param pluginId 插件id* @return PluginState*/@GetMapping(value = "/startPluginById")public ResponseEntity<String> startPluginById(String pluginId) {PluginState pluginState = pluginManager.startPlugin(pluginId);return ResponseEntity.ok(pluginState.toString());}/*** 停止插件** @param pluginId 插件id* @return PluginState*/@GetMapping(value = "/stopPluginById")public ResponseEntity<String> stopPluginById(String pluginId) {PluginState pluginState = pluginManager.stopPlugin(pluginId);return ResponseEntity.ok(pluginState.toString());}/*** 禁用插件** @param pluginId 插件id* @return boolean true表示成功*/@GetMapping(value = "/disablePluginById")public ResponseEntity<Boolean> disablePluginById(String pluginId) {boolean result = pluginManager.disablePlugin(pluginId);return ResponseEntity.ok(result);}/*** 启用插件** @param pluginId 插件id* @return boolean true表示成功*/@GetMapping(value = "/enablePluginById")public ResponseEntity<Boolean> enablePluginById(String pluginId) {boolean result = pluginManager.enablePlugin(pluginId);return ResponseEntity.ok(result);}/*** 卸载插件** @param pluginId 插件id* @return boolean true表示成功*/@GetMapping(value = "/unloadPluginById")public ResponseEntity<Boolean> unloadPluginById(String pluginId) {boolean result = pluginManager.unloadPlugin(pluginId);return ResponseEntity.ok(result);}/*** 加载插件** @return String*/@GetMapping(value = "/loadPlugins")public ResponseEntity<String> loadPlugins() {pluginManager.loadPlugins();//开启所有插件pluginManager.startPlugins();return ResponseEntity.ok("SUCCESS");}/*** 执行插件中的扩展点** @param pluginId 插件id* @return String 执行结果*/@GetMapping(value = "/executePluginExtensionHandlerById")public ResponseEntity<String> executePluginExtensionHandlerById(String pluginId) {List<Class<?>> extensionClasses = pluginManager.getExtensionClasses(pluginId);for (Class<?> extensionClass : extensionClasses) {if (extensionClass.getName().equals("pub.qingyun.service.impl.TestExtensionHandler")) {try {Class<?> clz = Class.forName("pub.qingyun.service.impl.TestExtensionHandler", true, Thread.currentThread().getContextClassLoader());TestExtensionHandler extensionHandler = (TestExtensionHandler) clz.newInstance();String execute = extensionHandler.execute("hello");extensionHandler.run();} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {throw new RuntimeException(e);}}}return ResponseEntity.ok("SUCCESS");}
}
相关文章:
PF4J+SpringBoot
plugin-common pom.xml相关配置 <groupId>pub.qingyun</groupId> <artifactId>plugin-common</artifactId> <version>0.0.1-SNAPSHOT</version> <description>插件配置类</description><dependency><groupId>or…...
设计模式11-原型模式
设计模式11-原型模式 写在前面对象创建模式典型模式原型模式动机结构代码推导应用特点要点总结 原型模式与工厂方法模式对比工厂方法模式原型模式什么时候用什么模式 写在前面 对象创建模式 通过对象创建模式绕开动态内存分配来避免创建过程中所导致的耦合过紧的问题。从而支…...
Tomcat长连接源码解析
长连接: 客户端发送Http请求至服务端,请求发送完之后socket连接不断开,可以继续接收下一个Http请求并且解析返回。接手并解析这些Http请求的时候socket连接不断开,这种过程被称为长连接。 需要注意的点就在于,在满足什么条件的情况…...
C++编程:实现一个跨平台安全的定时器Timer模块
文章目录 0. 概要1. 设计目标2. SafeTimer 类的实现2.1 头文件 safe_timer.h源文件 safe_timer.cpp 3. 工作流程图4. 单元测试 0. 概要 对于C应用编程,定时器模块是一个至关重要的组件。为了确保系统的可靠性和功能安全,我们需要设计一个高效、稳定的定…...
PyTorch的自动微分模块【含梯度基本数学原理详解】
文章目录 1、简介1.1、基本概念1.2、基本原理1.2.1、自动微分1.2.2、梯度1.2.3、梯度求导1.2.4、梯度下降法1.2.5、张量梯度举例 1.3、Autograd的高级功能 2、梯度基本计算2.1、单标量梯度2.2、单向量梯度的计算2.3、多标量梯度计算2.4、多向量梯度计算 3、控制梯度计算4、累计…...
AI 绘画|Midjourney设计Logo提示词
你是否已经看过许多别人分享的 MJ 咒语,却仍无法按照自己的想法画图?通过学习 MJ 的提示词逻辑后,你将能够更好地理解并创作自己的“咒语”。本文将详细拆解使用 MJ 设计 Logo 的逻辑,让你在阅读后即可轻松上手,制作出…...
LeNet实验 四分类 与 四分类变为多个二分类
目录 1. 划分二分类 2. 训练独立的二分类模型 3. 二分类预测结果代码 4. 二分类预测结果 5 改进训练模型 6 优化后 预测结果代码 7 优化后预测结果 8 训练四分类模型 9 预测结果代码 10 四分类结果识别 1. 划分二分类 可以根据不同的类别进行多个划分,以…...
【BUG】已解决:java.lang.reflect.InvocationTargetException
已解决:java.lang.reflect.InvocationTargetException 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页,我是博主英杰,211科班出身,就职于医疗科技公司,热衷分享知识,武汉城市开发…...
配置kali 的apt命令在线安装包的源为国内源
目录 一、安装VMware Tools 二、配置apt国内源 一、安装VMware Tools 点击安装 VMware Tools 后,会加载一个虚拟光驱,里面包含 VMware Tools 的安装包 鼠标右键单击 VMware Tools 的安装包,点击复制到 点击 主目录,再点击选择…...
JAVA 异步编程(线程安全)二
1、线程安全 线程安全是指你的代码所在的进程中有多个线程同时运行,而这些线程可能会同时运行这段代码,如果每次运行的代码结果和单线程运行的结果是一样的,且其他变量的值和预期的也是一样的,那么就是线程安全的。 一个类或者程序…...
Golang | Leetcode Golang题解之第260题只出现一次的数字III
题目: 题解: func singleNumber(nums []int) []int {xorSum : 0for _, num : range nums {xorSum ^ num}lsb : xorSum & -xorSumtype1, type2 : 0, 0for _, num : range nums {if num&lsb > 0 {type1 ^ num} else {type2 ^ num}}return []in…...
IDEA自带的Maven 3.9.x无法刷新http nexus私服
问题: 自建的私服,配置了域名,使用http协议,在IDEA中或本地Maven 3.9.x会出现报错,提示http被blocked,原因是Maven 3.8.1开始,Maven默认禁止使用HTTP仓库地址,只允许使用HTTPS仓库地…...
56、本地数据库迁移到阿里云
现有需求,本地数据库迁移到阿里云上。 库名xy102表 test01test02test01 test023条数据。1、登录阿里云界面创建免费试用ECS实列。 阿里云登录页 (aliyun.com)](https://account.aliyun.com/login/login.htm?oauth_callbackhttps%3A%2F%2Fusercenter2.aliyun.com%…...
新时代多目标优化【数学建模】领域的极致探索——数学规划模型
目录 例1 1.问题重述 2.基本模型 变量定义: 目标函数: 约束条件: 3.模型分析与假设 4.模型求解 5.LINGO代码实现 6.结果解释 编辑 7.敏感性分析 8.结果解释 例2 奶制品的销售计划 1.问题重述 编辑 2.基本模型 3.模…...
单例模式详解
文章目录 一、概述1.单例模式2.单例模式的特点3.单例模式的实现方法 二、单例模式的实现1. 饿汉式2. 懒汉式3. 双重校验锁4. 静态内部类5. 枚举 三、总结 一、概述 1.单例模式 单例模式(Singleton Pattern)是一种创建型设计模式,确保一个类…...
WebGIS主流的客户端框架比较|OpenLayers|Leaflet|Cesium
实现 WebGIS 应用的主流前端框架主要包括 OpenLayers、Leaflet、Mapbox GL JS 和 Cesium 等。每个框架都有其独特的功能和优势,适合不同的应用场景。 WebGIS主流前端框架的优缺点 前 端 框架优点缺点OpenLayers较重量级的开源库,二维GIS功能最丰富全面…...
【LabVIEW作业篇 - 2】:分数判断、按钮控制while循环暂停、单击按钮获取book文本
文章目录 分数判断按钮控制while循环暂停按钮控制单个while循环暂停 按钮控制多个while循环暂停单击按钮获取book文本 分数判断 限定整型数值输入控件值得输入范围,范围在0-100之间,判断整型数值输入控件的输入值。 输入范围在0-59之间,显示…...
Kafka架构详解之分区Partition
目录 一、简介二、架构三、分区Partition1.分区概念2.Offsets(偏移量)和消息的顺序3.分区如何为Kafka提供扩展能力4.producer写入策略5.consumer消费机制 一、简介 Apache Kafka 是分布式发布 - 订阅消息系统,在 kafka 官网上对 kafka 的定义…...
SSM之Mybatis
SSM之Mybatis 一、MyBatis简介1、MyBatis特性2、MyBatis的下载3、MyBatis和其他持久化层技术对比 二、MyBatis框架搭建三、MyBatis基础功能1、MyBatis核心配置文件2、MyBatis映射文件3、MyBatis实现增删改查4、MyBatis获取参数值的两种方式5、MyBatis查询功能6、MyBatis自定义映…...
Python list comprehension (列表推导式 - 列表解析式 - 列表生成式)
Python list comprehension {列表推导式 - 列表解析式 - 列表生成式} 1. Python list comprehension (列表推导式 - 列表解析式 - 列表生成式)2. Example3. ExampleReferences Python 中的列表解析式并不是用来解决全新的问题,只是为解决已有问题提供新的语法。 列…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...
如何配置一个sql server使得其它用户可以通过excel odbc获取数据
要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据,你需要完成以下配置步骤: ✅ 一、在 SQL Server 端配置(服务器设置) 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到:SQL Server 网络配…...
CSS3相关知识点
CSS3相关知识点 CSS3私有前缀私有前缀私有前缀存在的意义常见浏览器的私有前缀 CSS3基本语法CSS3 新增长度单位CSS3 新增颜色设置方式CSS3 新增选择器CSS3 新增盒模型相关属性box-sizing 怪异盒模型resize调整盒子大小box-shadow 盒子阴影opacity 不透明度 CSS3 新增背景属性ba…...
