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");
    }
}
相关推荐
冰淇淋烤布蕾7 分钟前
EasyExcel使用
java·开发语言·excel
拾荒的小海螺13 分钟前
JAVA:探索 EasyExcel 的技术指南
java·开发语言
Jakarta EE30 分钟前
正确使用primefaces的process和update
java·primefaces·jakarta ee
马剑威(威哥爱编程)38 分钟前
哇喔!20种单例模式的实现与变异总结
java·开发语言·单例模式
java—大象1 小时前
基于java+springboot+layui的流浪动物交流信息平台设计实现
java·开发语言·spring boot·layui·课程设计
ApiHug2 小时前
ApiSmart x Qwen2.5-Coder 开源旗舰编程模型媲美 GPT-4o, ApiSmart 实测!
人工智能·spring boot·spring·ai编程·apihug
魔道不误砍柴功2 小时前
探秘Spring Boot中的@Conditional注解
数据库·spring boot·oracle
杨哥带你写代码2 小时前
网上商城系统:Spring Boot框架的实现
java·spring boot·后端
camellias_2 小时前
SpringBoot(二十一)SpringBoot自定义CURL请求类
java·spring boot·后端
布川ku子2 小时前
[2024最新] java八股文实用版(附带原理)---Mysql篇
java·mysql·面试