有关java插件方面的问题
-
我是通过导入 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项目我都试过了。我上面的思想有没有哪里是错误的。还请大佬指点一下。谢谢!!
-
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) -
spring-boot
打包和 一般的 fat-jar 打包不一样他会按
spring-boot
独有的格式组织 jar 包 (总有二傻子把 spring-boot 的 规范当成 fat-jar 的规范)你应该使用 fat-jar 的打包方式