mamoe / mirai

高效率 QQ 机器人支持库
https://mirai.mamoe.net
GNU Affero General Public License v3.0
14.33k stars 2.53k forks source link

无法通过JvmPlugin的JvmPluginClassLoader获取到mirai-console的class文件资源 #2535

Closed ArgonarioD closed 1 year ago

ArgonarioD commented 1 year ago

问题描述

简明版: 在onEnable方法中调用该JvmPlugin类的ClassLoader的getResourceAsStream("net/mamoe/mirai/console/command/SimpleCommand.class")方法返回为null(但是loadClass是能够返回正确的Class的)

我的动机: 我在试图整合spring和mirai以简化mirai的开发。spring在初始化容器的时候会从ClassLoader中读取Component的父类字节码,我的Component继承了mirai-console的SimpleCommand类,我设置spring容器的ClassLoader为我的JvmPlugin类的ClassLoader,根据IDEA的debugger显示也就是JvmPluginClassLoaderN类。spring调用了该类的getResourceAsStream("net/mamoe/mirai/console/command/SimpleCommand.class")方法获取到了null导致容器初始化失败。

复现

override fun onEnable() {
    (this::class.java.classLoader.getResource("net/mamoe/mirai/console/command/SimpleCommand.class") ?: "null")
            .let { logger.info { it.toString() } }
}

logger会输出null

mirai-core 版本

2.14.0

bot-protocol

ANDROID_PHONE

其他组件版本

Running MiraiConsole v2.14.0, built on 2023-02-06 14:25:21. Frontend Terminal: version 2.14.0, provided by Mamoe Technologies

Permission Service: Built In Permission Service

Plugins: Hammer Spring Test v0.1.0

Object Pending Finalization Count: 0 committed init used max
Heap Memory 292.0MB 512.0MB 147.11MB 7.96GB
Non-Heap Memory 52.93MB 7.31MB 48.62MB -1

系统日志

No response

网络日志

No response

补充信息

使用语言为Kotlin,版本为1.8.0 在mcl环境下测试了以后和上文结果相同。 如果在这个ClassLoader中获取不到mirai的库class是设计的话,想要请问有没有什么方法来获取到这个class资源?我目前的临时解决方法就是直接用mcl的libs文件夹中的jar包来构建URLClassLoader,但这样做似乎不是很安全的样子(

cssxsh commented 1 year ago

为啥要在插件里塞一个大型框架

ArgonarioD commented 1 year ago

为啥要在插件里塞一个大型框架

框架本身设计和生态都很好,开发起来爽,资源占用也还可以接受(

cssxsh commented 1 year ago

为啥要在插件里塞一个大型框架

框架本身设计和生态都很好,开发起来爽,资源占用也还可以接受(

那也应该是反过来,spring 里加载 mirai,而不是 mirai 加载 spring

ArgonarioD commented 1 year ago

为啥要在插件里塞一个大型框架

框架本身设计和生态都很好,开发起来爽,资源占用也还可以接受(

那也应该是反过来,spring 里加载 mirai,而不是 mirai 加载 spring

emmmmm,为什么这样说呢? 我这样做是希望能够做到jvm插件对于console的目录结构无侵入式改变,并且

  1. spring的ioc容器本身是比较轻量的,对于性能等都没有太大的影响,对于插件的业务逻辑代码也是无侵入的
  2. 对于支持插件系统的mirai来说,不同插件之间的容器本身也应该是父子关系或无关,我个人认为除非需要提供插件的共享Bean,否则不应该由一个容器统一管理

不过讨论应用场景的问题会不会有点跑题了(((

zhaodice commented 1 year ago

试试看 双亲ClassLoader