mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-07 16:40:43 +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()
|
||||
|
||||
/**
|
||||
* 加载插件的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())
|
||||
}
|
||||
|
||||
//插件加载器导入插件jar
|
||||
pluginsClassLoader.loadPlugins(pluginsLocation)
|
||||
|
||||
//load plugin individually
|
||||
fun loadPlugin(description: PluginDescription): Boolean {
|
||||
if (!description.noCircularDepend) {
|
||||
@ -210,41 +207,31 @@ object PluginManager {
|
||||
|
||||
logger.info("loading plugin " + description.name)
|
||||
|
||||
try {
|
||||
val pluginClass = try{
|
||||
pluginsClassLoader.loadPluginMainClass(description.basePath)
|
||||
} 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
|
||||
}
|
||||
val jarFile = pluginsLocation[description.name]!!
|
||||
val pluginClass = try{
|
||||
pluginsLoader.loadPluginMainClassByJarFile(description.name,description.basePath,jarFile)
|
||||
} catch (e: ClassNotFoundException) {
|
||||
logger.error("failed to load plugin " + description.name + " , Main class not found under " + description.basePath)
|
||||
logger.error(e)
|
||||
return false
|
||||
pluginsLoader.loadPluginMainClassByJarFile(description.name,"${description.basePath}Kt",jarFile)
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
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)
|
||||
nameToPluginBaseMap.remove(plugin.pluginName)
|
||||
pluginDescriptions.remove(plugin.pluginName)
|
||||
//pluginsClassLoader.remove(plugin.pluginName)
|
||||
pluginsLoader.remove(plugin.pluginName)
|
||||
pluginsSequence.remove(plugin)
|
||||
}
|
||||
|
||||
@ -310,7 +308,7 @@ object PluginManager {
|
||||
}
|
||||
nameToPluginBaseMap.clear()
|
||||
pluginDescriptions.clear()
|
||||
pluginsClassLoader.clear()
|
||||
pluginsLoader.clear()
|
||||
pluginsSequence.clear()
|
||||
}
|
||||
|
||||
|
@ -1,33 +1,128 @@
|
||||
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.IOException
|
||||
import java.net.URLClassLoader
|
||||
|
||||
internal class PluginsClassLoader(private val parent: ClassLoader) {
|
||||
|
||||
private var cl : URLClassLoader? = null
|
||||
|
||||
/**
|
||||
* 加载多个插件
|
||||
*/
|
||||
fun loadPlugins(pluginsLocation: Map<String, File>) {
|
||||
cl = URLClassLoader(
|
||||
pluginsLocation.values.map { it.toURI().toURL() }.toTypedArray(),
|
||||
parent)
|
||||
internal class PluginsLoader(private val parentClassLoader: ClassLoader) {
|
||||
private val loggerName = "PluginsLoader"
|
||||
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 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<*>{
|
||||
return cl?.loadClass(name) ?: error("PluginsClassLoader has not yet run the loadPlugins func.")
|
||||
fun loadPluginMainClassByJarFile(pluginName:String, mainClass: String, jarFile:File): Class<*> {
|
||||
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