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

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请求至服务端&#xff0c;请求发送完之后socket连接不断开&#xff0c;可以继续接收下一个Http请求并且解析返回。接手并解析这些Http请求的时候socket连接不断开&#xff0c;这种过程被称为长连接。 需要注意的点就在于&#xff0c;在满足什么条件的情况…...

C++编程:实现一个跨平台安全的定时器Timer模块

文章目录 0. 概要1. 设计目标2. SafeTimer 类的实现2.1 头文件 safe_timer.h源文件 safe_timer.cpp 3. 工作流程图4. 单元测试 0. 概要 对于C应用编程&#xff0c;定时器模块是一个至关重要的组件。为了确保系统的可靠性和功能安全&#xff0c;我们需要设计一个高效、稳定的定…...

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 咒语&#xff0c;却仍无法按照自己的想法画图&#xff1f;通过学习 MJ 的提示词逻辑后&#xff0c;你将能够更好地理解并创作自己的“咒语”。本文将详细拆解使用 MJ 设计 Logo 的逻辑&#xff0c;让你在阅读后即可轻松上手&#xff0c;制作出…...

LeNet实验 四分类 与 四分类变为多个二分类

目录 1. 划分二分类 2. 训练独立的二分类模型 3. 二分类预测结果代码 4. 二分类预测结果 5 改进训练模型 6 优化后 预测结果代码 7 优化后预测结果 8 训练四分类模型 9 预测结果代码 10 四分类结果识别 1. 划分二分类 可以根据不同的类别进行多个划分&#xff0c;以…...

【BUG】已解决:java.lang.reflect.InvocationTargetException

已解决&#xff1a;java.lang.reflect.InvocationTargetException 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开发…...

配置kali 的apt命令在线安装包的源为国内源

目录 一、安装VMware Tools 二、配置apt国内源 一、安装VMware Tools 点击安装 VMware Tools 后&#xff0c;会加载一个虚拟光驱&#xff0c;里面包含 VMware Tools 的安装包 鼠标右键单击 VMware Tools 的安装包&#xff0c;点击复制到 点击 主目录&#xff0c;再点击选择…...

JAVA 异步编程(线程安全)二

1、线程安全 线程安全是指你的代码所在的进程中有多个线程同时运行&#xff0c;而这些线程可能会同时运行这段代码&#xff0c;如果每次运行的代码结果和单线程运行的结果是一样的&#xff0c;且其他变量的值和预期的也是一样的&#xff0c;那么就是线程安全的。 一个类或者程序…...

Golang | Leetcode Golang题解之第260题只出现一次的数字III

题目&#xff1a; 题解&#xff1a; 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私服

问题&#xff1a; 自建的私服&#xff0c;配置了域名&#xff0c;使用http协议&#xff0c;在IDEA中或本地Maven 3.9.x会出现报错&#xff0c;提示http被blocked&#xff0c;原因是Maven 3.8.1开始&#xff0c;Maven默认禁止使用HTTP仓库地址&#xff0c;只允许使用HTTPS仓库地…...

56、本地数据库迁移到阿里云

现有需求&#xff0c;本地数据库迁移到阿里云上。 库名xy102表 test01test02test01 test023条数据。1、登录阿里云界面创建免费试用ECS实列。 阿里云登录页 (aliyun.com)](https://account.aliyun.com/login/login.htm?oauth_callbackhttps%3A%2F%2Fusercenter2.aliyun.com%…...

新时代多目标优化【数学建模】领域的极致探索——数学规划模型

目录 例1 1.问题重述 2.基本模型 变量定义&#xff1a; 目标函数&#xff1a; 约束条件&#xff1a; 3.模型分析与假设 4.模型求解 5.LINGO代码实现 6.结果解释 ​编辑 7.敏感性分析 8.结果解释 例2 奶制品的销售计划 1.问题重述 ​编辑 2.基本模型 3.模…...

单例模式详解

文章目录 一、概述1.单例模式2.单例模式的特点3.单例模式的实现方法 二、单例模式的实现1. 饿汉式2. 懒汉式3. 双重校验锁4. 静态内部类5. 枚举 三、总结 一、概述 1.单例模式 单例模式&#xff08;Singleton Pattern&#xff09;是一种创建型设计模式&#xff0c;确保一个类…...

WebGIS主流的客户端框架比较|OpenLayers|Leaflet|Cesium

实现 WebGIS 应用的主流前端框架主要包括 OpenLayers、Leaflet、Mapbox GL JS 和 Cesium 等。每个框架都有其独特的功能和优势&#xff0c;适合不同的应用场景。 WebGIS主流前端框架的优缺点 前 端 框架优点缺点OpenLayers较重量级的开源库&#xff0c;二维GIS功能最丰富全面…...

【LabVIEW作业篇 - 2】:分数判断、按钮控制while循环暂停、单击按钮获取book文本

文章目录 分数判断按钮控制while循环暂停按钮控制单个while循环暂停 按钮控制多个while循环暂停单击按钮获取book文本 分数判断 限定整型数值输入控件值得输入范围&#xff0c;范围在0-100之间&#xff0c;判断整型数值输入控件的输入值。 输入范围在0-59之间&#xff0c;显示…...

Kafka架构详解之分区Partition

目录 一、简介二、架构三、分区Partition1.分区概念2.Offsets&#xff08;偏移量&#xff09;和消息的顺序3.分区如何为Kafka提供扩展能力4.producer写入策略5.consumer消费机制 一、简介 Apache Kafka 是分布式发布 - 订阅消息系统&#xff0c;在 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 中的列表解析式并不是用来解决全新的问题&#xff0c;只是为解决已有问题提供新的语法。 列…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

NPOI Excel用OLE对象的形式插入文件附件以及插入图片

static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...

【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error

在前端开发中&#xff0c;JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作&#xff08;如 Promise、async/await 等&#xff09;&#xff0c;开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝&#xff08;r…...

二维FDTD算法仿真

二维FDTD算法仿真&#xff0c;并带完全匹配层&#xff0c;输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...

Java数组Arrays操作全攻略

Arrays类的概述 Java中的Arrays类位于java.util包中&#xff0c;提供了一系列静态方法用于操作数组&#xff08;如排序、搜索、填充、比较等&#xff09;。这些方法适用于基本类型数组和对象数组。 常用成员方法及代码示例 排序&#xff08;sort&#xff09; 对数组进行升序…...

用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章

用 Rust 重写 Linux 内核模块实战&#xff1a;迈向安全内核的新篇章 ​​摘要&#xff1a;​​ 操作系统内核的安全性、稳定性至关重要。传统 Linux 内核模块开发长期依赖于 C 语言&#xff0c;受限于 C 语言本身的内存安全和并发安全问题&#xff0c;开发复杂模块极易引入难以…...

raid存储技术

1. 存储技术概念 数据存储架构是对数据存储方式、存储设备及相关组件的组织和规划&#xff0c;涵盖存储系统的布局、数据存储策略等&#xff0c;它明确数据如何存储、管理与访问&#xff0c;为数据的安全、高效使用提供支撑。 由计算机中一组存储设备、控制部件和管理信息调度的…...

react菜单,动态绑定点击事件,菜单分离出去单独的js文件,Ant框架

1、菜单文件treeTop.js // 顶部菜单 import { AppstoreOutlined, SettingOutlined } from ant-design/icons; // 定义菜单项数据 const treeTop [{label: Docker管理,key: 1,icon: <AppstoreOutlined />,url:"/docker/index"},{label: 权限管理,key: 2,icon:…...