在Main中不允许使用覆盖修饰符,但在scala中扩展App trait时允许使用覆盖修饰符

在Main中不允许使用覆盖修饰符,但在scala中扩展App trait时允许使用覆盖修饰符,scala,traits,Scala,Traits,我正在尝试为我的应用程序创建一个启动程序,并正在通过Apptrait和main方法来决定使用哪个启动程序。我发现两者之间唯一的区别是: (1) 引用对象的线程代码将被阻塞,直到静态初始化完成。但是,由于对象扩展应用程序的整个执行过程都发生在静态初始化期间,因此,如果并发代码必须与封闭对象同步,它将始终死锁 在我的例子中,我有一个Launcher,它基本上初始化了一个Kafkaloader对象,该对象继续运行Kafkapoll。下面是我的启动器特性: trait Launcher extends

我正在尝试为我的应用程序创建一个启动程序,并正在通过
App
trait和
main
方法来决定使用哪个启动程序。我发现两者之间唯一的区别是:

(1) 引用对象的线程代码将被阻塞,直到静态初始化完成。但是,由于对象扩展应用程序的整个执行过程都发生在静态初始化期间,因此,如果并发代码必须与封闭对象同步,它将始终死锁

在我的例子中,我有一个
Launcher
,它基本上初始化了一个
Kafka
loader对象,该对象继续运行
Kafka
poll。下面是我的
启动器
特性:

trait Launcher extends LazyLogging {
val config: Config
val actorSystem: ActorSystem
val sourceMessagesType = config.getString("app.source.dataType")
val targetTopic = config.getString("app.kafka.targetTopic")
val targetTopicPartitions =config.getInt("app.kafka.targetTopicPartitions")

val routingManager = HashedPartitionRoutingManager(targetTopic, targetTopicPartitions)
logger.info(s"Initializing MorpheusStreamDataLoader for $sourceMessagesType type")
sourceMessagesType.toLowerCase match {
case "json" => JSonDataLoader(config, routingManager)
case "avro" => AvroDataLoader(config, routingManager)
case _ => throw new IllegalArgumentException
  s"Messages of type ${sourceMessagesType.toLowerCase} are not supported.\n" 
 }
}
现在,为了启动我的应用程序,我试图找到哪种方法最适合使用,
App
main
方法。但是
main
方法实现根本不起作用:

object ClientLauncher extends  Launcher {
def main(args: Array[String]): Unit = {
override val config=ConfigFactory.load(args(0))
override val actorSystem: ActorSystem=ActorSystem("ClientActorSystem")
 }
}
当我这样做时,我在
override
修饰符上得到错误,这里不允许使用
override修饰符
。然而,如果我使用
App
trait,它不会给我任何编译时错误

object ClientLauncher extends App with Launcher {
override val config=ConfigFactory.load(args(0))
override val actorSystem: ActorSystem=ActorSystem("ClientActorSystem")
}

在阅读了几篇关于
App
trait和
main
的帖子后,我得到的信息是,除了使用
App
trait时发生的延迟初始化之外,没有其他区别。为什么
override
不适用于
main
方法而适用于
App
?启动应用程序的最佳方式是什么?

您需要将它们移到方法之外,以便它们是对象字段而不是局部变量

object ClientLauncher extends  Launcher {

  override val config=ConfigFactory.load()
  override val actorSystem: ActorSystem=ActorSystem("ClientActorSystem")

  def main(args: Array[String]): Unit = {
    /*code*/
  }
}
但是,通过这种方式,您将无法访问命令行参数或任何其他main本地参数

如果您需要访问该应用程序,并且不想扩展该应用程序,另一种方法是使用单独的类来扩展launcher

class ClientLauncher(configFile: String) extends  Launcher {
  override val config=ConfigFactory.load(configFile)
  override val actorSystem: ActorSystem=ActorSystem("ClientActorSystem")
}

object Main {
  def main(args: Array[String]): Unit = {
    new ClientLauncher(args(0))
  }
}
或者将这些参数作为系统属性而不是命令行参数传入

object ClientLauncher extends  Launcher {

  override val config=ConfigFactory.load(sys.props("configFile"))
  override val actorSystem: ActorSystem=ActorSystem("ClientActorSystem")

  def main(args: Array[String]): Unit = {
    /*code*/
  }
}
并在运行代码时传入系统属性

java -DconfigFile="config.conf" -jar myJar.jar

args(0)
无法在该位置被引用。但是如果我这样做,
args(0)
的作用域将被更改,并且它不再可用于配置。@右浏览器,您可以将其设为var并在main中赋值,使用其他类扩展启动器并重写这些值,或者继续使用App trait。@Explorer假设配置工厂来自typesafe配置库,您可以使用
ConfigFactory.load()
让它自动找到您的application.conf文件,而无需将其作为参数传入。另一个选择是将
args(0)
作为系统属性传递。我喜欢将config作为系统属性传递的想法,我对此一无所知,感谢您指出这一点。