在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作为系统属性传递的想法,我对此一无所知,感谢您指出这一点。