mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-09 19:50:27 +08:00
JvmPluginClassLoaderAccess
This commit is contained in:
parent
b0711ed9ab
commit
237320317e
@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
package net.mamoe.console.itest.serviceloader
|
package net.mamoe.console.itest.serviceloader
|
||||||
|
|
||||||
import net.mamoe.mirai.console.internal.plugin.JvmPluginClassLoaderN
|
|
||||||
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
|
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
|
||||||
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
|
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
|
||||||
import net.mamoe.mirai.utils.info
|
import net.mamoe.mirai.utils.info
|
||||||
@ -21,9 +20,10 @@ import kotlin.test.assertEquals
|
|||||||
|
|
||||||
internal object PMain : KotlinPlugin(JvmPluginDescription("net.mamoe.console.itest.serviceloader", "0.0.0")) {
|
internal object PMain : KotlinPlugin(JvmPluginDescription("net.mamoe.console.itest.serviceloader", "0.0.0")) {
|
||||||
init {
|
init {
|
||||||
val cl = PMain.javaClass.classLoader as JvmPluginClassLoaderN
|
val access = jvmPluginClassLoaderAccess
|
||||||
cl.pluginSharedCL.addLib(File("modules/module-service-loader-typedef-0.0.0.jar"))
|
val sharedCL = access.pluginSharedLibrariesClassLoader
|
||||||
cl.pluginSharedCL.addLib(File("modules/module-service-loader-impl-0.0.0.jar"))
|
access.addToPath(sharedCL, File("modules/module-service-loader-typedef-0.0.0.jar"))
|
||||||
|
access.addToPath(sharedCL, File("modules/module-service-loader-impl-0.0.0.jar"))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onEnable() {
|
override fun onEnable() {
|
||||||
|
@ -2157,6 +2157,7 @@ public abstract class net/mamoe/mirai/console/plugin/jvm/AbstractJvmPlugin : net
|
|||||||
public synthetic fun <init> (Lkotlin/coroutines/CoroutineContext;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
public synthetic fun <init> (Lkotlin/coroutines/CoroutineContext;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
public fun getAutoSaveIntervalMillis ()Lkotlin/ranges/LongRange;
|
public fun getAutoSaveIntervalMillis ()Lkotlin/ranges/LongRange;
|
||||||
public final fun getDataHolderName ()Ljava/lang/String;
|
public final fun getDataHolderName ()Ljava/lang/String;
|
||||||
|
protected final fun getJvmPluginClassLoaderAccess ()Lnet/mamoe/mirai/console/plugin/jvm/JvmPluginClassLoaderAccess;
|
||||||
public final fun getLoader ()Lnet/mamoe/mirai/console/plugin/jvm/JvmPluginLoader;
|
public final fun getLoader ()Lnet/mamoe/mirai/console/plugin/jvm/JvmPluginLoader;
|
||||||
public synthetic fun getLoader ()Lnet/mamoe/mirai/console/plugin/loader/PluginLoader;
|
public synthetic fun getLoader ()Lnet/mamoe/mirai/console/plugin/loader/PluginLoader;
|
||||||
public final fun permissionId (Ljava/lang/String;)Lnet/mamoe/mirai/console/permission/PermissionId;
|
public final fun permissionId (Ljava/lang/String;)Lnet/mamoe/mirai/console/permission/PermissionId;
|
||||||
@ -2213,6 +2214,15 @@ public final class net/mamoe/mirai/console/plugin/jvm/JvmPlugin$Companion {
|
|||||||
public final synthetic fun onLoad (Lnet/mamoe/mirai/console/plugin/jvm/JvmPlugin;Lnet/mamoe/mirai/console/extension/PluginComponentStorage;)V
|
public final synthetic fun onLoad (Lnet/mamoe/mirai/console/plugin/jvm/JvmPlugin;Lnet/mamoe/mirai/console/extension/PluginComponentStorage;)V
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract interface class net/mamoe/mirai/console/plugin/jvm/JvmPluginClassLoaderAccess {
|
||||||
|
public abstract fun addToPath (Ljava/lang/ClassLoader;Ljava/io/File;)V
|
||||||
|
public abstract fun downloadAndAddToPath (Ljava/lang/ClassLoader;Ljava/util/Collection;)V
|
||||||
|
public abstract fun getPluginClassLoader ()Ljava/lang/ClassLoader;
|
||||||
|
public abstract fun getPluginFile ()Ljava/io/File;
|
||||||
|
public abstract fun getPluginIndependentLibrariesClassLoader ()Ljava/lang/ClassLoader;
|
||||||
|
public abstract fun getPluginSharedLibrariesClassLoader ()Ljava/lang/ClassLoader;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract interface class net/mamoe/mirai/console/plugin/jvm/JvmPluginDescription : net/mamoe/mirai/console/plugin/description/PluginDescription {
|
public abstract interface class net/mamoe/mirai/console/plugin/jvm/JvmPluginDescription : net/mamoe/mirai/console/plugin/description/PluginDescription {
|
||||||
public static final field Companion Lnet/mamoe/mirai/console/plugin/jvm/JvmPluginDescription$Companion;
|
public static final field Companion Lnet/mamoe/mirai/console/plugin/jvm/JvmPluginDescription$Companion;
|
||||||
public static fun loadFromResource ()Lnet/mamoe/mirai/console/plugin/jvm/JvmPluginDescription;
|
public static fun loadFromResource ()Lnet/mamoe/mirai/console/plugin/jvm/JvmPluginDescription;
|
||||||
|
@ -12,6 +12,7 @@ package net.mamoe.mirai.console.internal.plugin
|
|||||||
|
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
import net.mamoe.mirai.console.MiraiConsole
|
||||||
import net.mamoe.mirai.console.plugin.jvm.ExportManager
|
import net.mamoe.mirai.console.plugin.jvm.ExportManager
|
||||||
|
import net.mamoe.mirai.console.plugin.jvm.JvmPluginClassLoaderAccess
|
||||||
import net.mamoe.mirai.utils.*
|
import net.mamoe.mirai.utils.*
|
||||||
import org.eclipse.aether.artifact.Artifact
|
import org.eclipse.aether.artifact.Artifact
|
||||||
import org.eclipse.aether.graph.DependencyFilter
|
import org.eclipse.aether.graph.DependencyFilter
|
||||||
@ -163,6 +164,7 @@ internal class DynLibClassLoader : URLClassLoader {
|
|||||||
|
|
||||||
@Suppress("JoinDeclarationAndAssignment")
|
@Suppress("JoinDeclarationAndAssignment")
|
||||||
internal class JvmPluginClassLoaderN : URLClassLoader {
|
internal class JvmPluginClassLoaderN : URLClassLoader {
|
||||||
|
val openaccess: JvmPluginClassLoaderAccess = OpenAccess()
|
||||||
val file: File
|
val file: File
|
||||||
val ctx: JvmPluginsLoadingCtx
|
val ctx: JvmPluginsLoadingCtx
|
||||||
val sharedLibrariesLogger: DynLibClassLoader
|
val sharedLibrariesLogger: DynLibClassLoader
|
||||||
@ -224,10 +226,12 @@ internal class JvmPluginClassLoaderN : URLClassLoader {
|
|||||||
internal var declaredFilter: ExportManager? = null
|
internal var declaredFilter: ExportManager? = null
|
||||||
|
|
||||||
val sharedClLoadedDependencies = mutableSetOf<String>()
|
val sharedClLoadedDependencies = mutableSetOf<String>()
|
||||||
|
val privateClLoadedDependencies = mutableSetOf<String>()
|
||||||
internal fun containsSharedDependency(
|
internal fun containsSharedDependency(
|
||||||
dependency: String
|
dependency: String
|
||||||
): Boolean {
|
): Boolean {
|
||||||
if (dependency in sharedClLoadedDependencies) return true
|
if (dependency in sharedClLoadedDependencies) return true
|
||||||
|
if (dependency in privateClLoadedDependencies) return true
|
||||||
return dependencies.any { it.containsSharedDependency(dependency) }
|
return dependencies.any { it.containsSharedDependency(dependency) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,6 +286,7 @@ internal class JvmPluginClassLoaderN : URLClassLoader {
|
|||||||
sharedClLoadedDependencies.add(artifact.depId())
|
sharedClLoadedDependencies.add(artifact.depId())
|
||||||
} else {
|
} else {
|
||||||
pluginIndependentCL.addLib(lib)
|
pluginIndependentCL.addLib(lib)
|
||||||
|
privateClLoadedDependencies.add(artifact.depId())
|
||||||
}
|
}
|
||||||
logger.debug { "Linked $artifact $linkType <${if (shared) pluginSharedCL else pluginIndependentCL}>" }
|
logger.debug { "Linked $artifact $linkType <${if (shared) pluginSharedCL else pluginIndependentCL}>" }
|
||||||
}
|
}
|
||||||
@ -432,6 +437,50 @@ internal class JvmPluginClassLoaderN : URLClassLoader {
|
|||||||
return "JvmPluginClassLoader{${file.name}}"
|
return "JvmPluginClassLoader{${file.name}}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inner class OpenAccess : JvmPluginClassLoaderAccess {
|
||||||
|
override val pluginFile: File
|
||||||
|
get() = this@JvmPluginClassLoaderN.file
|
||||||
|
|
||||||
|
override val pluginClassLoader: ClassLoader
|
||||||
|
get() = this@JvmPluginClassLoaderN
|
||||||
|
|
||||||
|
override val pluginSharedLibrariesClassLoader: ClassLoader
|
||||||
|
get() = pluginSharedCL
|
||||||
|
override val pluginIndependentLibrariesClassLoader: ClassLoader
|
||||||
|
get() = pluginIndependentCL
|
||||||
|
|
||||||
|
private val permitted by lazy {
|
||||||
|
arrayOf(
|
||||||
|
this@JvmPluginClassLoaderN,
|
||||||
|
pluginSharedCL,
|
||||||
|
pluginIndependentCL,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addToPath(classLoader: ClassLoader, file: File) {
|
||||||
|
if (classLoader !in permitted) {
|
||||||
|
throw IllegalArgumentException("Unsupported classloader or cross plugin accessing: $classLoader")
|
||||||
|
}
|
||||||
|
if (classLoader == this@JvmPluginClassLoaderN) {
|
||||||
|
this@JvmPluginClassLoaderN.addURL(file.toURI().toURL())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
classLoader as DynLibClassLoader
|
||||||
|
classLoader.addLib(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun downloadAndAddToPath(classLoader: ClassLoader, dependencies: Collection<String>) {
|
||||||
|
if (classLoader !in permitted) {
|
||||||
|
throw IllegalArgumentException("Unsupported classloader or cross plugin accessing: $classLoader")
|
||||||
|
}
|
||||||
|
if (classLoader === this@JvmPluginClassLoaderN) {
|
||||||
|
throw IllegalArgumentException("Only support download dependencies to `plugin[Shared/Independent]LibrariesClassLoader`")
|
||||||
|
}
|
||||||
|
this@JvmPluginClassLoaderN.linkLibraries(
|
||||||
|
linkedLogger, dependencies, classLoader === pluginSharedCL
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val JavaSystemPlatformClassLoader: ClassLoader by lazy {
|
private val JavaSystemPlatformClassLoader: ClassLoader by lazy {
|
||||||
|
@ -14,6 +14,7 @@ package net.mamoe.mirai.console.plugin.jvm
|
|||||||
import net.mamoe.mirai.console.data.AutoSavePluginDataHolder
|
import net.mamoe.mirai.console.data.AutoSavePluginDataHolder
|
||||||
import net.mamoe.mirai.console.data.PluginConfig
|
import net.mamoe.mirai.console.data.PluginConfig
|
||||||
import net.mamoe.mirai.console.data.PluginData
|
import net.mamoe.mirai.console.data.PluginData
|
||||||
|
import net.mamoe.mirai.console.internal.plugin.JvmPluginClassLoaderN
|
||||||
import net.mamoe.mirai.console.internal.plugin.JvmPluginInternal
|
import net.mamoe.mirai.console.internal.plugin.JvmPluginInternal
|
||||||
import net.mamoe.mirai.console.permission.PermissionId
|
import net.mamoe.mirai.console.permission.PermissionId
|
||||||
import net.mamoe.mirai.console.permission.PermissionService
|
import net.mamoe.mirai.console.permission.PermissionService
|
||||||
@ -77,6 +78,21 @@ public abstract class AbstractJvmPlugin @JvmOverloads constructor(
|
|||||||
|
|
||||||
@ConsoleExperimentalApi
|
@ConsoleExperimentalApi
|
||||||
public override val autoSaveIntervalMillis: LongRange = 30.secondsToMillis..10.minutesToMillis
|
public override val autoSaveIntervalMillis: LongRange = 30.secondsToMillis..10.minutesToMillis
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 [JvmPluginClassLoaderAccess]
|
||||||
|
*
|
||||||
|
* 注: 仅插件通过 console 内置插件加载器加载时可用
|
||||||
|
*
|
||||||
|
* @since 2.12
|
||||||
|
*/
|
||||||
|
protected val jvmPluginClassLoaderAccess: JvmPluginClassLoaderAccess by lazy {
|
||||||
|
val classLoader = this@AbstractJvmPlugin.javaClass.classLoader
|
||||||
|
if (classLoader is JvmPluginClassLoaderN) {
|
||||||
|
return@lazy classLoader.openaccess
|
||||||
|
}
|
||||||
|
error("jvmPluginClassLoaderAccess not available for $classLoader")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
||||||
|
*
|
||||||
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
|
*
|
||||||
|
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.console.plugin.jvm
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态注册类搜索路径
|
||||||
|
*
|
||||||
|
* @since 2.12
|
||||||
|
* @see AbstractJvmPlugin.jvmPluginClassLoaderAccess
|
||||||
|
*/
|
||||||
|
public interface JvmPluginClassLoaderAccess {
|
||||||
|
public val pluginFile: File
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件本体的 [ClassLoader], 负责加载插件本身的类数据
|
||||||
|
*
|
||||||
|
* JVM NAME: `${pluginFile.name}`
|
||||||
|
*/
|
||||||
|
public val pluginClassLoader: ClassLoader
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件所使用的依赖, 可共享, 当其他插件依赖于当前插件时, 其他插件可以从此 [ClassLoader] 搜索类引用
|
||||||
|
*
|
||||||
|
* JVM NAME: ${pluginFile.name}[shared]
|
||||||
|
*/
|
||||||
|
public val pluginSharedLibrariesClassLoader: ClassLoader
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件内部使用的依赖, 不公开给其他插件, 其他插件搜索时不会搜索到此插件的依赖
|
||||||
|
*
|
||||||
|
* JVM NAME: ${pluginFile.name}[private]
|
||||||
|
*/
|
||||||
|
public val pluginIndependentLibrariesClassLoader: ClassLoader
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 [file] 加入 [classLoader] 的搜索路径内
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException 当 [classLoader] 不是 [pluginClassLoader],
|
||||||
|
* [pluginIndependentLibrariesClassLoader], [pluginSharedLibrariesClassLoader] 时抛出
|
||||||
|
*/
|
||||||
|
@kotlin.jvm.Throws(IllegalArgumentException::class)
|
||||||
|
public fun addToPath(classLoader: ClassLoader, file: File)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载依赖, 并注册进 [classLoader]
|
||||||
|
*
|
||||||
|
* 注: 如果需要同时修改 [pluginSharedLibrariesClassLoader] 和 [pluginIndependentLibrariesClassLoader],
|
||||||
|
* 请先对 [pluginSharedLibrariesClassLoader] 以避免出现不和预期的问题
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException 当 [classLoader] 不是
|
||||||
|
* [pluginSharedLibrariesClassLoader], [pluginIndependentLibrariesClassLoader]
|
||||||
|
* 时抛出
|
||||||
|
* @throws Exception 网络错误 / 依赖未找到
|
||||||
|
*/
|
||||||
|
@kotlin.jvm.Throws(IllegalArgumentException::class, Exception::class)
|
||||||
|
public fun downloadAndAddToPath(classLoader: ClassLoader, dependencies: Collection<String>)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user