scala 从JAR加载类时发现URLClassLoader NoClassDefFound异常

hfsqlsce  于 2023-03-18  发布在  Scala
关注(0)|答案(1)|浏览(142)

我正在尝试写我自己的小插件加载程序:

package some.package.plugins

import org.clapper.classutil.{ClassFinder, ClassInfo}
import wvlet.log.LogSupport
import java.io.File
import java.net.{URL, URLClassLoader}

object PluginManager extends LogSupport {

  val PLUGIN_DIRECTOR = "./plugins/"
  val PLUGIN_INTERFACE = "package.Plugin"

  val jars: List[File] = new File(PLUGIN_DIRECTOR).listFiles.filter(_.getPath.endsWith(".jar")).toList
  private val pluginMap : Map[String,(ClassInfo,File)] = {
    jars.flatMap {
      jar =>
        val finder = ClassFinder(List(jar))
        println(finder.getClasses().map(_.interfaces).toList)
        finder.getClasses().filter(_.interfaces.contains(PLUGIN_INTERFACE)).map {
          info =>
            info.name.split("\\.").last -> (info, jar)
        }
    }.toMap
  }

  def getPlugins : Set[String] = pluginMap.keySet

  def loadPlugins(name : String) : AnalysisPlugin = {
    val classInfo : (ClassInfo,File) = pluginMap.getOrElse(name,throw new IllegalArgumentException(s"the plugin $name does not exist"))
    val urls : List[URL] = List(classInfo._2.toURI.toURL)
    val childClassLoader = URLClassLoader.newInstance(urls.toArray, ClassLoader.getSystemClassLoader)
    info(s"loading plugin ${classInfo._1.name}")
    val c: Class[_] = childClassLoader.loadClass(classInfo._1.name)
    assert(c.getConstructors.length == 1)
    c.getConstructors.head.newInstance().asInstanceOf[AnalysisPlugin]
  }

}

我使用ClassFinderClassInfo来标识.jar中实现PLUGIN_INTERFACE的所有类。输出确认我确实找到了实现PLUGIN_INTERFACE的类。然后,我使用URLClassLoader(与childClassLoader.loadClass一起提供)来加载相应的类,但我得到了NoClassDefFound异常。
这里的问题似乎是接口类,即,应该使不同插件对插件管理器透明的接口。package.Plugin是不能加载的类。
如何使用URLClassLoader加载包含在.jar中的类。

9gm1akwq

9gm1akwq1#

我不理解底层逻辑,但您需要为URLClassLoader提供一个不同的父类加载器,经过一些模糊处理后,我成功地使用包含main函数的对象的类加载器运行了代码:

def loadPlugins(name : String) : Option[AnalysisPlugin] = {
    val classInfo: (ClassInfo, File) = pluginMap.getOrElse(name, throw new IllegalArgumentException(s"the plugin $name does not exist"))
    val urls: List[URL] = List(classInfo._2.toURI.toURL)
    val parentClassLoader = Main.getClass.getClassLoader
    val childClassLoader = URLClassLoader.newInstance(urls.toArray, parentClassLoader)
    try {
      info(s"loading plugin ${classInfo._1.name}")
      Some(Class.forName(classInfo._1.name,true, childClassLoader).newInstance().asInstanceOf[AnalysisPlugin])
    } catch {
      case x : NoClassDefFoundError =>
        error(x)
        error(s"plugin $name cannot be loaded check the plugin directory and make sure it is contained")
        None
    } finally {
      childClassLoader.close()
    }
  }

相关问题