我正在Scala开展多个SBT项目。我将核心内容提取到单独的SBT项目中。这包括处理配置,第三方库(init RMQ客户端,init Redis客户端等)和一些模型。
所以我组织了一些事情,例如在trait中加载配置然后我在需要它的地方混合这个特性,然后使用config
trait中定义的Configuration
方法,它为特定环境加载配置(基于环境变量)。我为数据库做了同样的事情,所以我加载PostgreSQL,打开连接,然后在我需要的地方混合使用该特性,并使用database
方法,我可以用它来执行查询等。
你认为这是好方法吗?优点是我不必在每个项目中处理数据库连接和初始化,而且代码也要短得多。但是,关闭连接存在一个问题。在哪里关闭数据库混合的特征中的连接?
对此主题的任何帮助表示赞赏。感谢
阿梅尔
答案 0 :(得分:1)
关于连接,你应该在完成连接后关闭它们(返回池),这与混合实现是正交的。
至于配置等,我喜欢这种方法,但问题在于,大多数时候你想要加载config
之类的东西是单身,但如果你只是做像
trait Configuration {
val config = loadConfig
}
class Foo with Configuration
class Bar with Configuration
val f1 = new Foo
val f2 = new Foo
val b1 = new Bar
val b2 = new Bar
然后,您最终会加载配置的四个不同副本。
解决此问题的一种方法是将loadConfig
委托给单个对象:
object Configuration {
val config = loadConfig
}
trait Configuration {
def config = Configration.config
}
这样可行,但是使单元测试和覆盖功能变得更加困难(如果我希望有时从数据库加载配置怎么办?)
另一种可能性是代理类:
trait Configuration {
def loadConfig: Config
lazy val config: Config = loadConfig
}
class ConfigurationProxy(cfg: Configuration) extends Configuration {
def loadConfig = cfg.config
}
object Main extends App with Configuration {
def loadConfig = ??? // executed only one per application
...
}
class Foo extends ConfigurationProxy(Main)
class Bar extends ConfigurationProxy(Main)
val f1 = new Foo
val f2 = new Foo
val b1 = new Bar
val b2 = new Bar
现在,所有四个变量都在查看相同的Config
实例。
但是如果你在某个地方有一个需要Configuration
的函数,你仍然可以通过以下任何一个:
def connectToDB(cfg: Configuration) = ???
connectToDB(Main)
connectToDB(f1)
connectToDB(b2)
等