MiraiForum

    • 注册
    • 登录
    • 搜索
    • 热门
    • 最新
    • 未解决
    • 标签
    • 群组
    • 友情链接

    有关java插件方面的问题

    开发交流
    2
    3
    232
    正在加载更多帖子
    • 从旧到新
    • 从新到旧
    • 最多赞同
    回复
    • 在新帖中回复
    登录后回复
    此主题已被删除。只有拥有主题管理权限的用户可以查看。
    • W
      wolfAndTime 最后由 编辑

      我是通过导入 mirai-core-jvm 和 mirai-core-api-jvm 和kotlin 相关的maven来构建项目的,是一个springboot项目,也写了相关的前端页面,现在想把功能单独抽出来写成插件,我在网上看了java怎么写插件,也做了个demo试了下,用的是java的spi思想(我看论坛里的kotlin写的插件格式都是一样的),下面是加载插件的类,也是网上找的

      public class PluginLoader {
      
          private static final Logger LOGGER = LoggerFactory.getLogger(PluginLoader.class);
      
          public static List<IPluginService> loadPlugins() throws MalformedURLException {
              List<IPluginService> plugins = new ArrayList<>();
      
              File parentDir = new File(PLUGIN_PATH);
              File[] files = parentDir.listFiles();
              if (null == files) {
                  return Collections.emptyList();
              }
      
              // 从目录下筛选出所有jar文件
              List<File> jarFiles = Arrays.stream(files)
                      .filter(file -> file.getName().endsWith(".jar"))
                      .collect(Collectors.toList());
      
              URL[] urls = new URL[jarFiles.size()];
              for (int i = 0; i < jarFiles.size(); i++) {
                  // 加上 "file:" 前缀表示本地文件
                  urls[i] = new URL("file:" + jarFiles.get(i).getAbsolutePath());
              }
              URLClassLoader urlClassLoader = new URLClassLoader(urls);
              // 使用 ServiceLoader 以SPI的方式加载插件包中的 IPluginService 实现类
              ServiceLoader<IPluginService> serviceLoader = ServiceLoader.load(IPluginService.class, urlClassLoader);
              for (IPluginService iPluginService : serviceLoader) {
                  plugins.add(iPluginService);
                  LOGGER.info("插件 "+iPluginService.name() + " 加载成功");
              }
              return plugins;
          }
      

      下面是要实现的接口

      public interface IPluginService {
      
          /**
           * 插件功能入口方法
           */
          void service();
      
          /**
           * 插件名成,通常用于展示在界面
           *
           * @return 插件名称
           */
          String name();
      
          /**
           * 表示当前插件的版本
           *
           * @return 插件版本号
           */
          String version();
      
      }
      

      现在有个问题,当打包主程序时,如果使用

      <build>
      	<plugins>
      		<plugin>
      			<groupId>org.springframework.boot</groupId>
      			<artifactId>spring-boot-maven-plugin</artifactId>
      			<version>2.2.5.RELEASE</version>
      		</plugin>
      	</plugins>
      </build>
      

      打包,插件项目引用主程序打包出来的jar的时候,会在编译时就找不到对应的IPluginService

      如果不用上面那段打包,插件项目就能正常打包,但是打包出来让主程序运行时会出现java.lang.NoClassDefFoundError,提示IPluginService 没有定义
      我确定 插件META-INF/services 文件夹下的文件和文件内容没有写错,因为报错的那段是

      //这是PluginLoader类的方法里的代码
              ServiceLoader<IPluginService> serviceLoader = ServiceLoader.load(IPluginService.class, urlClassLoader);
      

      我想问一下,如果非得是maven项目做主程序,插件项目该怎么引入主程序的jar才能让插件能正常运行?插件项目是普通的java项目和maven项目我都试过了。我上面的思想有没有哪里是错误的。还请大佬指点一下。谢谢!!

      1 条回复 最后回复 回复 引用 0
      • W
        wolfAndTime 最后由 编辑

        NoClassDefFoundError 内部还有个 java.lang.ClassNotFoundException 报错,抱歉刚刚没注意

        Caused by: java.lang.ClassNotFoundException: com.xx.service.IPluginService
        java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:476)
        java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589)

        1 条回复 最后回复 回复 引用 0
        • cssxsh
          cssxsh 最后由 编辑

          spring-boot 打包和 一般的 fat-jar 打包不一样

          他会按 spring-boot 独有的格式组织 jar 包 (总有二傻子把 spring-boot 的 规范当成 fat-jar 的规范)

          你应该使用 fat-jar 的打包方式

          1 条回复 最后回复 回复 引用 0
          • 1 / 1
          • First post
            Last post
          Powered by Mamoe Technologies & NodeBB | 友情链接 | 服务监控 | Contact