Skip to content

Commit 5c1c40a

Browse files
committed
Allow override console non-hard-link dependencies
1 parent 3987492 commit 5c1c40a

File tree

5 files changed

+90
-8
lines changed

5 files changed

+90
-8
lines changed
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
com.zaxxer:SparseBitSet:1.2
2+
3+
## Test console non-hard-link override
4+
org.bouncycastle:bcprov-jdk15on:1.63

mirai-console/backend/integration-test/testers/plugin-dynamic-dependencies-download/src/P.kt

+8
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ package net.mamoe.console.integrationtest.ep.pddd
1212
import net.mamoe.mirai.console.extension.PluginComponentStorage
1313
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
1414
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
15+
import kotlin.test.assertEquals
1516

1617
/*
1718
PluginDynamicDependenciesDownload: 测试动态运行时下载
@@ -26,5 +27,12 @@ internal object P : KotlinPlugin(
2627
override fun PluginComponentStorage.onLoad() {
2728
Class.forName("com.google.gson.Gson") // shared
2829
Class.forName("com.zaxxer.sparsebits.SparseBitSet") // private
30+
31+
// console-non-hard-link dependency
32+
// mirai-core used 1.64 current
33+
assertEquals(
34+
"1.63.0",
35+
Class.forName("org.bouncycastle.LICENSE").`package`.implementationVersion
36+
)
2937
}
3038
}

mirai-console/backend/mirai-console/build.gradle.kts

+14-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@ kotlin {
3030
explicitApiWarning()
3131
}
3232

33-
configurations.register("consoleRuntimeClasspath")
33+
configurations.create("consoleRuntimeClasspath").attributes {
34+
attribute(Usage.USAGE_ATTRIBUTE,
35+
project.objects.named(Usage::class.java, Usage.JAVA_API)
36+
)
37+
}
3438

3539
dependencies {
3640
compileAndTestRuntime(project(":mirai-core-api"))
@@ -59,6 +63,8 @@ dependencies {
5963
testApi(`kotlin-stdlib-jdk8`)
6064

6165
"consoleRuntimeClasspath"(project)
66+
"consoleRuntimeClasspath"(project(":mirai-core-utils"))
67+
"consoleRuntimeClasspath"(project(":mirai-core-api"))
6268
"consoleRuntimeClasspath"(project(":mirai-core"))
6369
}
6470

@@ -90,5 +96,12 @@ tasks.getByName("compileKotlin").dependsOn(
9096
)
9197
)
9298

99+
val graphDump = DependencyDumper.registerDumpClassGraph(project, "consoleRuntimeClasspath", "allclasses.txt")
100+
tasks.named<Copy>("processResources").configure {
101+
from(graphDump) {
102+
into("META-INF/mirai-console")
103+
}
104+
}
105+
93106
configurePublishing("mirai-console")
94107
configureBinaryValidator(null)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2019-2022 Mamoe Technologies and contributors.
3+
*
4+
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
5+
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
6+
*
7+
* https://github.com/mamoe/mirai/blob/dev/LICENSE
8+
*/
9+
10+
package net.mamoe.mirai.console.internal.plugin
11+
12+
// Same as LazyLoad
13+
internal object AllDependenciesClassesHolder {
14+
@JvmField
15+
internal val allclasses = AllDependenciesClassesHolder::class.java
16+
.getResourceAsStream("/META-INF/mirai-console/allclasses.txt")!!
17+
.bufferedReader().use { reader ->
18+
reader.useLines { lines ->
19+
lines.filterNot { it.isBlank() }
20+
.toHashSet()
21+
}
22+
}
23+
24+
@JvmField
25+
internal val appClassLoader: ClassLoader = AllDependenciesClassesHolder::class.java.classLoader
26+
}

mirai-console/backend/mirai-console/src/internal/plugin/JvmPluginClassLoader.kt

+39-7
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import java.util.zip.ZipFile
2626
Class resolving:
2727
2828
|
29-
`- Resolve standard classes: by super class loader.
29+
`- Resolve standard classes: hard linked by console (@see AllDependenciesClassesHolder)
3030
`- Resolve classes in shared libraries (Shared in all plugins)
3131
|
3232
|-===== SANDBOX =====
@@ -35,6 +35,7 @@ Class resolving:
3535
`- Resolve classes in independent libraries (Can only be loaded by current plugin)
3636
`- Resolve classes in current jar.
3737
`- Resolve classes from other plugin jar
38+
`- Resolve by AppClassLoader
3839
3940
*/
4041

@@ -58,6 +59,17 @@ internal class DynLibClassLoader(
5859
}
5960
}
6061

62+
internal fun loadClassInThisClassLoader(name: String): Class<*>? {
63+
synchronized(getClassLoadingLock(name)) {
64+
findLoadedClass(name)?.let { return it }
65+
try {
66+
return findClass(name)
67+
} catch (ignored: ClassNotFoundException) {
68+
}
69+
}
70+
return null
71+
}
72+
6173
internal fun addLib(url: URL) {
6274
addURL(url)
6375
}
@@ -75,6 +87,7 @@ internal class DynLibClassLoader(
7587
internal class JvmPluginClassLoaderN : URLClassLoader {
7688
val file: File
7789
val ctx: JvmPluginsLoadingCtx
90+
val sharedLibrariesLogger: DynLibClassLoader
7891

7992
val dependencies: MutableCollection<JvmPluginClassLoaderN> = hashSetOf()
8093

@@ -85,6 +98,7 @@ internal class JvmPluginClassLoaderN : URLClassLoader {
8598
private constructor(file: File, ctx: JvmPluginsLoadingCtx, unused: Unit) : super(
8699
arrayOf(), ctx.sharedLibrariesLoader
87100
) {
101+
this.sharedLibrariesLogger = ctx.sharedLibrariesLoader
88102
this.file = file
89103
this.ctx = ctx
90104
init0()
@@ -94,6 +108,7 @@ internal class JvmPluginClassLoaderN : URLClassLoader {
94108
file.name,
95109
arrayOf(), ctx.sharedLibrariesLoader
96110
) {
111+
this.sharedLibrariesLogger = ctx.sharedLibrariesLoader
97112
this.file = file
98113
this.ctx = ctx
99114
init0()
@@ -184,12 +199,26 @@ internal class JvmPluginClassLoaderN : URLClassLoader {
184199
internal fun resolvePluginPublicClass(name: String): Class<*>? {
185200
if (pluginMainPackages.contains(name.pkgName())) {
186201
if (declaredFilter?.isExported(name) == false) return null
187-
return loadClass(name)
202+
synchronized(getClassLoadingLock(name)) {
203+
findLoadedClass(name)?.let { return it }
204+
return super.findClass(name)
205+
}
188206
}
189207
return null
190208
}
191209

192-
override fun findClass(name: String): Class<*> {
210+
override fun loadClass(name: String): Class<*> {
211+
if (name.startsWith("io.netty") || name in AllDependenciesClassesHolder.allclasses) {
212+
return AllDependenciesClassesHolder.appClassLoader.loadClass(name)
213+
}
214+
if (name.startsWith("net.mamoe.mirai.")) { // Avoid plugin classing cheating
215+
try {
216+
return AllDependenciesClassesHolder.appClassLoader.loadClass(name)
217+
} catch (ignored: ClassNotFoundException) {
218+
}
219+
}
220+
sharedLibrariesLogger.loadClassInThisClassLoader(name)?.let { return it }
221+
193222
// Search dependencies first
194223
dependencies.forEach { dependency ->
195224
dependency.resolvePluginSharedLibAndPluginClass(name)?.let { return it }
@@ -202,15 +231,18 @@ internal class JvmPluginClassLoaderN : URLClassLoader {
202231
}
203232

204233
try {
205-
return super.findClass(name)
234+
synchronized(getClassLoadingLock(name)) {
235+
findLoadedClass(name)?.let { return it }
236+
return super.findClass(name)
237+
}
206238
} catch (error: ClassNotFoundException) {
207-
// Finally, try search from other plugins
239+
// Finally, try search from other plugins and console system
208240
ctx.pluginClassLoaders.forEach { other ->
209-
if (other !== this) {
241+
if (other !== this && other !in dependencies) {
210242
other.resolvePluginPublicClass(name)?.let { return it }
211243
}
212244
}
213-
throw error
245+
return AllDependenciesClassesHolder.appClassLoader.loadClass(name)
214246
}
215247
}
216248

0 commit comments

Comments
 (0)