Binding/Injecting 使用 Guice 的 Scala 函数(不是整个 class)?

Binding/Injecting a Scala function (not whole class) using Guice?

我想将 UserDao 对象的 byId 方法注入到 Authentication 对象的构造函数中。我想避免注入整个 class.

// Has def byId(id: UserId): Option[User]
bind(classOf[UserDao]).asEagerSingleton()

// Something like this
bindMethod(classOf[UserDao], _.byId)

// Constructor takes a (UserId) => Option[User] function
bind(classOf[Authentication]).asEagerSingleton()

我在 Play Framework 中使用 Guice。任何建议表示赞赏

其实你要的是封装?

如果是这样,我建议使用这样的代码:

// User model
case class User(id: UUID, name: String)

trait AuthenticationUserDao{
  def findById: Option[User]
}

class UserDao extends AuthenticationUserDao {
  override def findById: Option[User] = ???
  def add(user: User): Boolean = ???
  def delete(userId: UUID): Boolean = ???
}

// ...

class Authentication @Inject() (
                                 authenticationUserDao: AuthenticationUserDao
                               ) extends Controller {

  // Here only the method findById is available (not tested, but i guest it's the case here)

  def findUser(userId: UUID) = Action {
    authenticationUserDao.findById(userId)
  }

}

// ...

bind(classOf[UserDao]).to(classOf[AuthenticationUserDao])

希望我已经明白了。

你问这个问题是对的,因为它可以大大简化测试。诀窍是使用 @Provides 注释:

TL;DR

class MyController @Inject() (byId: (UserId) => Option[User]) extends Controller { ... }

@Provides
def userDao(aDependency: Any): UserDao = // return UserDao, note aDependency will be injected

@Provides
def byId: (UserId) => Option[User] = userDao.byId // note: this method will call the other @Provides method 'userDao'

说明

最终 byId: (UserId) => Option[User] 转换为 scala.Function1[UserId, Option[User]] 但是您可以使用语法糖来声明函数依赖关系:

class MyController @Inject() (_addTwo: (Int, Int) => Int) extends Controller {

  def addTwo(a: Int, b: Int) = Action {
    Ok(_addTwo(a, b).toString) // call the injected function 
  }

}

然后在您的 Module.scala 中创建一个方法,其中 returns 函数:

@Provides
def addTwo: (Int, Int) => Int = (a, b) => a + b

您可以在 @Provides 方法中执行所有常见的 Scala 操作,例如返回部分应用的函数:

@Provides
def addTwo: (Int, Int) => Int = addThree(0, _:Int, _:Int)

def addThree(a: Int, b: Int, c: Int): Int = a + b + c

为避免冲突,您还可以使用 @Named 注释:

class MyController @Inject() (@Named("addTwo") _addTwo: (Int, Int) => Int, 
                              @Named("subtractTwo") _subTwo: (Int, Int) => Int) 
                              extends Controller { ... }

@Provides
@Named("addTwo")
def addTwo: (Int, Int) => Int = (a, b) => a + b

@Provides
@Named("subtractTwo")
def subTwo: (Int, Int) => Int = (a, b) => a - b