mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-24 06:50:08 +08:00
change PluginsClassLoader and change method name by 'loadPluginMainClass' to 'loadPluginMainClassByJarFile'
This commit is contained in:
parent
c9f0195f8e
commit
6460de75a2
@ -48,9 +48,9 @@ object PluginManager {
|
|||||||
private val pluginDescriptions: MutableMap<String, PluginDescription> = mutableMapOf()
|
private val pluginDescriptions: MutableMap<String, PluginDescription> = mutableMapOf()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载插件的ClassLoader
|
* 加载插件的PluginsLoader
|
||||||
*/
|
*/
|
||||||
private val pluginsClassLoader: PluginsClassLoader = PluginsClassLoader(this.javaClass.classLoader)
|
private val pluginsLoader: PluginsLoader = PluginsLoader(this.javaClass.classLoader)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 插件优先级队列
|
* 插件优先级队列
|
||||||
@ -181,9 +181,6 @@ object PluginManager {
|
|||||||
checkNoCircularDepends(it, it.depends, mutableListOf())
|
checkNoCircularDepends(it, it.depends, mutableListOf())
|
||||||
}
|
}
|
||||||
|
|
||||||
//插件加载器导入插件jar
|
|
||||||
pluginsClassLoader.loadPlugins(pluginsLocation)
|
|
||||||
|
|
||||||
//load plugin individually
|
//load plugin individually
|
||||||
fun loadPlugin(description: PluginDescription): Boolean {
|
fun loadPlugin(description: PluginDescription): Boolean {
|
||||||
if (!description.noCircularDepend) {
|
if (!description.noCircularDepend) {
|
||||||
@ -210,41 +207,31 @@ object PluginManager {
|
|||||||
|
|
||||||
logger.info("loading plugin " + description.name)
|
logger.info("loading plugin " + description.name)
|
||||||
|
|
||||||
try {
|
val jarFile = pluginsLocation[description.name]!!
|
||||||
val pluginClass = try{
|
val pluginClass = try{
|
||||||
pluginsClassLoader.loadPluginMainClass(description.basePath)
|
pluginsLoader.loadPluginMainClassByJarFile(description.name,description.basePath,jarFile)
|
||||||
} catch (e: ClassNotFoundException) {
|
|
||||||
pluginsClassLoader.loadPluginMainClass("${description.basePath}Kt")
|
|
||||||
}
|
|
||||||
|
|
||||||
return try {
|
|
||||||
val subClass = pluginClass!!.asSubclass(PluginBase::class.java)
|
|
||||||
|
|
||||||
lastPluginName = description.name
|
|
||||||
val plugin: PluginBase =
|
|
||||||
subClass.kotlin.objectInstance ?: subClass.getDeclaredConstructor().apply {
|
|
||||||
againstPermission()
|
|
||||||
}.newInstance()
|
|
||||||
plugin.dataFolder // initialize right now
|
|
||||||
|
|
||||||
description.loaded = true
|
|
||||||
logger.info("successfully loaded plugin " + description.name + " version " + description.version + " by " + description.author)
|
|
||||||
logger.info(description.info)
|
|
||||||
|
|
||||||
nameToPluginBaseMap[description.name] = plugin
|
|
||||||
pluginDescriptions[description.name] = description
|
|
||||||
plugin.pluginName = description.name
|
|
||||||
pluginsSequence.add(plugin)//按照实际加载顺序加入队列
|
|
||||||
true
|
|
||||||
} catch (e: ClassCastException) {
|
|
||||||
logger.error("failed to load plugin " + description.name + " , Main class does not extends PluginBase ")
|
|
||||||
false
|
|
||||||
}
|
|
||||||
} catch (e: ClassNotFoundException) {
|
} catch (e: ClassNotFoundException) {
|
||||||
logger.error("failed to load plugin " + description.name + " , Main class not found under " + description.basePath)
|
pluginsLoader.loadPluginMainClassByJarFile(description.name,"${description.basePath}Kt",jarFile)
|
||||||
logger.error(e)
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val subClass = pluginClass.asSubclass(PluginBase::class.java)
|
||||||
|
|
||||||
|
lastPluginName = description.name
|
||||||
|
val plugin: PluginBase =
|
||||||
|
subClass.kotlin.objectInstance ?: subClass.getDeclaredConstructor().apply {
|
||||||
|
againstPermission()
|
||||||
|
}.newInstance()
|
||||||
|
plugin.dataFolder // initialize right now
|
||||||
|
|
||||||
|
description.loaded = true
|
||||||
|
logger.info("successfully loaded plugin " + description.name + " version " + description.version + " by " + description.author)
|
||||||
|
logger.info(description.info)
|
||||||
|
|
||||||
|
nameToPluginBaseMap[description.name] = plugin
|
||||||
|
pluginDescriptions[description.name] = description
|
||||||
|
plugin.pluginName = description.name
|
||||||
|
pluginsSequence.add(plugin)//按照实际加载顺序加入队列
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -252,7 +239,18 @@ object PluginManager {
|
|||||||
pluginsSequence.clear()
|
pluginsSequence.clear()
|
||||||
|
|
||||||
pluginsFound.values.forEach {
|
pluginsFound.values.forEach {
|
||||||
loadPlugin(it)
|
try{
|
||||||
|
// 尝试加载插件
|
||||||
|
loadPlugin(it)
|
||||||
|
}catch (e: Throwable) {
|
||||||
|
pluginsLoader.remove(it.name)
|
||||||
|
when(e){
|
||||||
|
is ClassCastException -> logger.error("failed to load plugin " + it.name + " , Main class does not extends PluginBase",e)
|
||||||
|
is ClassNotFoundException -> logger.error("failed to load plugin " + it.name + " , Main class not found under " + it.basePath,e)
|
||||||
|
is NoClassDefFoundError -> logger.error("failed to load plugin " + it.name + " , dependent class not found.",e)
|
||||||
|
else -> logger.error("failed to load plugin " + it.name,e)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -297,7 +295,7 @@ object PluginManager {
|
|||||||
plugin.disable(exception)
|
plugin.disable(exception)
|
||||||
nameToPluginBaseMap.remove(plugin.pluginName)
|
nameToPluginBaseMap.remove(plugin.pluginName)
|
||||||
pluginDescriptions.remove(plugin.pluginName)
|
pluginDescriptions.remove(plugin.pluginName)
|
||||||
//pluginsClassLoader.remove(plugin.pluginName)
|
pluginsLoader.remove(plugin.pluginName)
|
||||||
pluginsSequence.remove(plugin)
|
pluginsSequence.remove(plugin)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +308,7 @@ object PluginManager {
|
|||||||
}
|
}
|
||||||
nameToPluginBaseMap.clear()
|
nameToPluginBaseMap.clear()
|
||||||
pluginDescriptions.clear()
|
pluginDescriptions.clear()
|
||||||
pluginsClassLoader.clear()
|
pluginsLoader.clear()
|
||||||
pluginsSequence.clear()
|
pluginsSequence.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,33 +1,128 @@
|
|||||||
package net.mamoe.mirai.console.plugins
|
package net.mamoe.mirai.console.plugins
|
||||||
|
|
||||||
|
import net.mamoe.mirai.console.MiraiConsole
|
||||||
|
import net.mamoe.mirai.utils.SimpleLogger
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
import java.net.URLClassLoader
|
import java.net.URLClassLoader
|
||||||
|
|
||||||
internal class PluginsClassLoader(private val parent: ClassLoader) {
|
internal class PluginsLoader(private val parentClassLoader: ClassLoader) {
|
||||||
|
private val loggerName = "PluginsLoader"
|
||||||
private var cl : URLClassLoader? = null
|
private val pluginLoaders = linkedMapOf<String,PluginClassLoader>()
|
||||||
|
private val classesCache = mutableMapOf<String, Class<*>>()
|
||||||
/**
|
private val logger = SimpleLogger(loggerName) { p, message, e ->
|
||||||
* 加载多个插件
|
MiraiConsole.logger(p, "[${loggerName}]", 0, message)
|
||||||
*/
|
MiraiConsole.logger(p, "[${loggerName}]", 0, e)
|
||||||
fun loadPlugins(pluginsLocation: Map<String, File>) {
|
|
||||||
cl = URLClassLoader(
|
|
||||||
pluginsLocation.values.map { it.toURI().toURL() }.toTypedArray(),
|
|
||||||
parent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清除所有插件加载器
|
* 清除所有插件加载器
|
||||||
*/
|
*/
|
||||||
fun clear() {
|
fun clear() {
|
||||||
cl?.close()
|
val iterator = pluginLoaders.iterator()
|
||||||
|
while(iterator.hasNext()){
|
||||||
|
val plugin = iterator.next()
|
||||||
|
var cl = ""
|
||||||
|
try {
|
||||||
|
cl = plugin.value.toString()
|
||||||
|
plugin.value.close()
|
||||||
|
iterator.remove()
|
||||||
|
}catch (e: Throwable){
|
||||||
|
logger.error("Plugin(${plugin.key}) can't not close its ClassLoader(${cl})",e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
classesCache.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载
|
* 移除单个插件加载器
|
||||||
*/
|
*/
|
||||||
|
fun remove(pluginName: String): Boolean {
|
||||||
|
pluginLoaders[pluginName]?.close() ?: return false
|
||||||
|
pluginLoaders.remove(pluginName)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
fun loadPluginMainClass(name: String) : Class<*>{
|
fun loadPluginMainClassByJarFile(pluginName:String, mainClass: String, jarFile:File): Class<*> {
|
||||||
return cl?.loadClass(name) ?: error("PluginsClassLoader has not yet run the loadPlugins func.")
|
try {
|
||||||
|
if(!pluginLoaders.containsKey(pluginName)){
|
||||||
|
pluginLoaders[pluginName] = PluginClassLoader(pluginName,jarFile, this, parentClassLoader)
|
||||||
|
}
|
||||||
|
return Class.forName(mainClass,true,pluginLoaders[pluginName])
|
||||||
|
}catch (e : ClassNotFoundException){
|
||||||
|
throw ClassNotFoundException("PluginsClassLoader(${pluginName}) can't load this pluginMainClass:${mainClass}",e)
|
||||||
|
}catch (e : Throwable){
|
||||||
|
throw Throwable("init or load class error",e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试加载插件的依赖,无则返回null
|
||||||
|
*/
|
||||||
|
fun loadDependentClass(name: String): Class<*>? {
|
||||||
|
var c: Class<*>? = null
|
||||||
|
// 尝试从缓存中读取
|
||||||
|
if (classesCache.containsKey(name)) {
|
||||||
|
c = classesCache[name]
|
||||||
|
}
|
||||||
|
// 然后再交给插件的classloader来加载依赖
|
||||||
|
if (c == null) {
|
||||||
|
pluginLoaders.values.forEach {
|
||||||
|
try {
|
||||||
|
c = it.findClass(name, false)
|
||||||
|
return@forEach
|
||||||
|
} catch (e: ClassNotFoundException) {/*nothing*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addClassCache(name: String, clz: Class<*>) {
|
||||||
|
synchronized(classesCache) {
|
||||||
|
if (!classesCache.containsKey(name)) {
|
||||||
|
classesCache[name] = clz
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class PluginClassLoader(private val pluginName: String,files: File, private val pluginsLoader: PluginsLoader, parent: ClassLoader) :
|
||||||
|
URLClassLoader(arrayOf((files.toURI().toURL())), parent) {
|
||||||
|
private val classesCache = mutableMapOf<String, Class<*>?>()
|
||||||
|
|
||||||
|
override fun findClass(name: String): Class<*>? {
|
||||||
|
return this.findClass(name, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findClass(name: String, isSearchDependent: Boolean): Class<*>? {
|
||||||
|
var clz: Class<*>? = null
|
||||||
|
// 缓存中找
|
||||||
|
if (classesCache.containsKey(name)) {
|
||||||
|
|
||||||
|
return classesCache[name]
|
||||||
|
}
|
||||||
|
// 是否寻找依赖
|
||||||
|
if (isSearchDependent) {
|
||||||
|
clz = pluginsLoader.loadDependentClass(name)
|
||||||
|
}
|
||||||
|
// 交给super去findClass
|
||||||
|
if (clz == null) {
|
||||||
|
clz = super.findClass(name)
|
||||||
|
}
|
||||||
|
// 加入缓存
|
||||||
|
if (clz != null) {
|
||||||
|
pluginsLoader.addClassCache(name, clz)
|
||||||
|
}
|
||||||
|
// 加入缓存
|
||||||
|
synchronized(classesCache) {
|
||||||
|
classesCache[name] = clz
|
||||||
|
}
|
||||||
|
return clz
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
super.close()
|
||||||
|
classesCache.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user