PF4J+SpringBoot

plugin-common

pom.xml相关配置

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

java 复制代码
public interface IExtensionHandler extends Runnable, ExtensionPoint {
    String execute(String param);
}

实现类

java 复制代码
import org.pf4j.Extension;
import pub.qingyun.service.IExtensionHandler;

@Extension
public class TestExtensionHandler implements IExtensionHandler {
    @Override
    public void run() {
        System.out.println("TestExtensionHandler run...");
    }

    @Override
    public String execute(String param) {
        System.out.println("TestExtensionHandler.execute...param=" + param);
        return param;
    }
}

plugin-spring-boot

pom.xml相关配置

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

java 复制代码
@Configuration
public class PluginConfig {
    
    // 插件目录,对应插件jar包/zip
    @Value("${pf4j.pluginPath}")
    private String pf4jPluginPath;

    @Bean
    public 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;
    }
}

控制层实现

java 复制代码
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 {

    @Resource
    private 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");
    }
}
相关推荐
技术无疆14 分钟前
快速开发与维护:探索 AndroidAnnotations
android·java·android studio·android-studio·androidx·代码注入
罗政3 小时前
[附源码]超简洁个人博客网站搭建+SpringBoot+Vue前后端分离
vue.js·spring boot·后端
架构文摘JGWZ3 小时前
Java 23 的12 个新特性!!
java·开发语言·学习
拾光师4 小时前
spring获取当前request
java·后端·spring
aPurpleBerry4 小时前
neo4j安装启动教程+对应的jdk配置
java·neo4j
我是苏苏4 小时前
Web开发:ABP框架2——入门级别的增删改查Demo
java·开发语言
xujinwei_gingko4 小时前
Spring IOC容器Bean对象管理-Java Config方式
java·spring
2301_789985944 小时前
Java语言程序设计基础篇_编程练习题*18.29(某个目录下的文件数目)
java·开发语言·学习
IT学长编程4 小时前
计算机毕业设计 教师科研信息管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·毕业设计·springboot·毕业论文·计算机毕业设计选题·计算机毕业设计开题报告·教师科研管理系统
m0_571957584 小时前
Java | Leetcode Java题解之第406题根据身高重建队列
java·leetcode·题解