我正在与Guice合作,并有一个设计问题。我的应用程序包含几个模块:
myapp-persistence必须有单独的HibernateSessionFactory。这是通过Hibernate设计的。 没问题我可以用Guice解决它:
class MyAppPersistenceModule extends AbstractModule {
override def configure(): Unit = {
bind(classOf[SomeStuff])
bind(classOf[ClientDao])
bind(classOf[CustomerDao])
bind(classOf[SessionFactory]).toProvider(classOf[HibernateSessionFactoryProvider]).asEagerSingleton()
}
@Provides
def provideDatabaseConnectionConfiguration: DatabaseConnectionConfiguration = {
DatabaseConnectionConfiguration.fromSysEnv
}
}
将 DatabaseConnectionConfiguration 传递给该单例的问题。 myapp-persistence模块并不关心如何获得该配置。现在它取自sys变量。
myapp-rest是play-app,它想从application.conf读取conf并使用Guice将其注入其他组件。 myapp-backend或多或少相同。
现在我被锁定了
@Provides
def provideDatabaseConnectionConfiguration: DatabaseConnectionConfiguration = {
DatabaseConnectionConfiguration.fromSysEnv
}
我不明白如何为myapp-rest和myapp-backend灵活配置。
UPD 根据回答,我是这样做的:
定义特征
trait DbConfProvider {
def dbConf: DbConf
}
Singleton工厂现在依赖于提供者:
class HibernateSessionFactoryProvider @Inject()(dbConfProvider: DbConfProvider) extends Provider[SessionFactory] {
}
myapp-persistence模块使用所有piblic持久性模块DAO公开public guice模块。
myapp-persistence具有仅用于测试目的的模块。 myapp-persistence注入器加载模块如下所述:
class MyAppPersistenceDbConfModule extends AbstractModule {
override def configure(): Unit = {
bind(classOf[DbConfProvider]).to(classOf[DbConfSysEnvProvider])
}
}
DbConfSysEnvProvider从sys env读取数据库连接设置。非生产用例。
Play app拥有自己的conf机制。我已将自定义模块添加到app conf:
# play-specific config
play.modules.enabled += "common.components.MyAppPersistenceDbConfModule"
# public components from myapp-persistence module.
play.modules.enabled += "com.myapp.persistence.connection.PersistenceModule"
我的配置服务:
@Singleton
class ConfigurationService @Inject()(configuration: Configuration) extends DbConfProvider {
...}
答案 0 :(得分:3)
我不是Play特定设置的专家,但通常这种设计问题可以通过以下方式之一解决:
没有默认值。从上游模块中删除DatabaseConnectionConfiguration的绑定(myapp-persistence),并根据需要在每个下游模块(myapp-backend,myapp-rest)中定义它。
默认为覆盖。像你一样保持DatabaseConnectionConfiguration的默认绑定,在那里实现最常见的配置策略。在需要时使用Guice Modules.override(..) API在下游模块中覆盖它。
跨模块实现统一的配置机制,不依赖于使用的特定框架。 (例如Bootique,建立在Guice之上......虽然没有将它用于Play)。
我个人更喜欢方法#3,但在没有类似Bootique的情况下,#2是一个很好的替代品。