为何无法将伴生对象传入函数?Silhouette框架环境构建疑问
这是个很典型的类型匹配问题,我来帮你拆解一下核心原因和对应的解决办法:
核心问题:类型不兼容
首先看一下你提到的Environment.apply方法签名里的authenticatorServiceImpl参数要求:
def apply[E <: Env]( identityServiceImpl: IdentityService[E#I], authenticatorServiceImpl: AuthenticatorService[E#A], // 重点关注这里 requestProvidersImpl: Seq[RequestProvider], eventBusImpl: EventBus )
这里的AuthenticatorService[E#A]要求传入的认证器服务实例,必须是针对你的自定义Environment类型E中定义的A类型成员的实现。
而SessionAuthenticatorService的伴生对象(object SessionAuthenticatorService)提供的apply方法,返回的是AuthenticatorService[SessionAuthenticator]——也就是专门针对SessionAuthenticator这个具体认证器类型的服务实现。
两者类型不匹配的原因通常有以下几种:
1. 你的Environment的A类型成员不是SessionAuthenticator
如果你定义的Environment类型里,A指向的是其他认证器类型(比如JWTAuthenticator),那自然无法传入SessionAuthenticatorService的实例:
// 错误示例:A类型不匹配 trait MyEnv extends Env { type I = User type A = JWTAuthenticator // 这里不是SessionAuthenticator }
此时E#A是JWTAuthenticator,而SessionAuthenticatorService实例的类型是AuthenticatorService[SessionAuthenticator],两者完全不兼容。
2. 你直接传入了伴生对象本身,而不是它的实例
注意:SessionAuthenticatorService是伴生对象,它本身的类型是SessionAuthenticatorService.type,而不是AuthenticatorService[E#A]。你需要调用它的apply方法来创建一个符合要求的实例,而不是直接传对象本身。
比如不能这样写:
// 错误示例:直接传伴生对象 val env = Environment[MyEnv]( identityService, SessionAuthenticatorService, // 这里错了,这是对象本身,不是实例 requestProviders, eventBus )
3. 类型参数的不变性限制
Silhouette的AuthenticatorService的类型参数A是不变的,这意味着AuthenticatorService[SessionAuthenticator]不能被当作AuthenticatorService[SomeSubtypeOfSessionAuthenticator]或者AuthenticatorService[SomeSupertypeOfSessionAuthenticator]使用,必须严格匹配类型。
解决办法
步骤1:确保Environment的A类型是SessionAuthenticator
先修正你的自定义Environment,让它的A成员指向SessionAuthenticator:
trait MyEnv extends Env { type I = User // 替换成你的实际用户类型 type A = SessionAuthenticator // 指定为SessionAuthenticator }
步骤2:正确构建SessionAuthenticatorService实例
调用伴生对象的apply方法,传入所需的依赖(比如SessionAuthenticatorSettings、Crypter、IDGenerator、Clock)来创建实例:
import com.mohiva.play.silhouette.impl.authenticators.SessionAuthenticatorSettings import play.api.libs.crypto.Crypter import com.mohiva.play.silhouette.api.util.{IDGenerator, Clock} // 假设你已经有这些依赖的实例 val crypter: Crypter = ... val idGenerator: IDGenerator = ... val clock: Clock = ... val sessionAuthenticatorService = SessionAuthenticatorService( settings = SessionAuthenticatorSettings(), // 可根据需求配置 crypter = crypter, idGenerator = idGenerator, clock = clock )
步骤3:创建Environment实例
现在你就可以把正确的实例传入Environment.apply了:
val identityService: IdentityService[User] = ... // 你的用户服务实现 val requestProviders: Seq[RequestProvider] = Seq(CookieRequestProvider()) // 按需配置 val eventBus: EventBus = EventBus() val env: Environment[MyEnv] = Environment[MyEnv]( identityServiceImpl = identityService, authenticatorServiceImpl = sessionAuthenticatorService, requestProvidersImpl = requestProviders, eventBusImpl = eventBus )
内容的提问来源于stack exchange,提问作者Manu Chadha

