动态类加载Scala类型

时间:2017-03-19 09:49:57

标签: scala classloader

我有以下Scala类层次结构:

abstract class BaseModule(val appConf : AppConfig) {
  // ...
}

class SimpleModule(appConf : AppConfig) extends BaseModule(appConf) {
  // ...
}

class FairlyComplexModule(appConf : AppConfig) extends BaseModule(appConf) {
  // ...
}

// dozens of other BaseModule subclasses...

在运行时,我的应用程序将接受一个String输入参数,用于实例化BaseModule子类的完全限定类名,但代码将不知道它是哪个具体子类将会。所以我有:

val moduleFQCN = loadFromInputArgs()  // ex: "com.example.myapp.SimpleModule"
val moduleClass = Class.forName(moduleFQCN)
println(s"Found ${moduleFQCN} on the runtime classpath.")
val module = Class.forName(moduleFQCN).getConstructor(classOf[AppConfig]).newInstance(appConf).asInstanceOf[BaseModule]

所以这样,输入指定在类路径上查找哪个BaseModule子类,然后进行实例化。上面的前三行执行得很好,我看到了println火。但是上面的最后一行引发了异常:

Exception in thread "main" java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    <rest of stacktrace omitted for brevity>

所以显然我在尝试创建SimpleModule子类的实例时做错了,只是无法弄清楚它是什么。有什么想法吗?

1 个答案:

答案 0 :(得分:4)

您可能失败了,因为您在没有任何参数的情况下调用newInstance(),但未找到默认构造函数,因此实例化失败。

试试这个:

Class.forName(moduleFQCN).getConstructor(classOf[AppConfig])
.newInstance(appConf).asInstanceOf[BaseModule]

其中appConfAppConfig的实例,并且是用{。}}实例化BaseModule的参数。