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");
    }
}
相关推荐
弗拉唐19 分钟前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi771 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
2401_857610031 小时前
SpringBoot社团管理:安全与维护
spring boot·后端·安全
少说多做3431 小时前
Android 不同情况下使用 runOnUiThread
android·java
知兀1 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
蓝黑20202 小时前
IntelliJ IDEA常用快捷键
java·ide·intellij-idea
Ysjt | 深2 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++
凌冰_2 小时前
IDEA2023 SpringBoot整合MyBatis(三)
spring boot·后端·mybatis
码农飞飞2 小时前
深入理解Rust的模式匹配
开发语言·后端·rust·模式匹配·解构·结构体和枚举