为什么在Play Framework中使用@Singleton对Scala的对象?
我一直在 Scala使用 Play! Framework近一年.我目前使用版本 2.5.x. 我知道Play中控制器的发展,以及开发人员被迫离开静态对象路由. 我也知道Guice的使用情况. 如果您下载activator并运行: activator new my-test-app play-scala Activator将为您生成一个模板项目. 我的测试,应用程序/应用程序/服务/ Counter.scala package services import java.util.concurrent.atomic.AtomicInteger import javax.inject._ /** * This trait demonstrates how to create a component that is injected * into a controller. The trait represents a counter that returns a * incremented number each time it is called. */ trait Counter { def nextCount(): Int } /** * This class is a concrete implementation of the [[Counter]] trait. * It is configured for Guice dependency injection in the [[Module]] * class. * * This class has a `Singleton` annotation because we need to make * sure we only use one counter per application. Without this * annotation we would get a new instance every time a [[Counter]] is * injected. */ @Singleton class AtomicCounter extends Counter { private val atomicCounter = new AtomicInteger() override def nextCount(): Int = atomicCounter.getAndIncrement() } 您还可以在this文件中看到它的用法: 我的测试,应用程序/应用/控制器/ CountController.scala package controllers import javax.inject._ import play.api._ import play.api.mvc._ import services.Counter /** * This controller demonstrates how to use dependency injection to * bind a component into a controller class. The class creates an * `Action` that shows an incrementing count to users. The [[Counter]] * object is injected by the Guice dependency injection system. */ @Singleton class CountController @Inject() (counter: Counter) extends Controller { /** * Create an action that responds with the [[Counter]]'s current * count. The result is plain text. This `Action` is mapped to * `GET /count` requests by an entry in the `routes` config file. */ def count = Action { Ok(counter.nextCount().toString) } } 这意味着每个具有@Inject()(counter:Counter)构造函数的控制器都将收到与Counter相同的实例. 所以我的问题是: 为什么使用@Singleton然后@Inject它进入一个控制器,在这个例子你可以只使用一个Scala对象? 例: 我的测试,应用程序/应用程序/服务/ Counter.scala package services trait ACounter { def nextCount: Int } object Counter with ACounter { private val atomicCounter = new AtomicInteger() def nextCount(): Int = atomicCounter.getAndIncrement() } 使用它像这样: 我的测试,应用程序/应用/控制器/ CountController.scala package controllers import javax.inject._ import play.api._ import play.api.mvc._ import services.{Counter,ACounter} /** * This controller demonstrates how to use dependency injection to * bind a component into a controller class. The class creates an * `Action` that shows an incrementing count to users. The [[Counter]] * object is injected by the Guice dependency injection system. */ @Singleton class CountController extends Controller { //depend on abstractions val counter: ACounter = Counter def count = Action { Ok(counter.nextCount().toString) } } 有什么不同?注射是首选,为什么? 解决方法
注射是首选吗?一般是的
使用依赖注入的几个优点: >控制器与Counter的具体实现分离. >如果要使用对象,则必须更改控制器以指向不同的实现. EG Counter2.nextCount().toString >您可以使用Guice自定义绑定来更改测试期间的实现 >让我们说,在Counter里面你正在做一个WS调用.这可能会导致单元测试困难.如果您使用Guice进行依赖注入,则可以覆盖Counter和AtomicCounter之间的绑定,以指向专门针对测试编写的脱机版Counter.有关使用Guice进行测试的更多信息,请参阅here. 另请参阅Play已经迁移到DI的motivations. 我一般说,因为我看到依赖注入使用Spring和其他Java框架非常错误.我会说你应该使用自己的判断,但是错误地使用DI for Play. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |