New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Singleton classes #236

Closed
sandokandias opened this Issue Aug 28, 2015 · 7 comments

Comments

2 participants
@sandokandias

sandokandias commented Aug 28, 2015

Hi. I realized that depending on the HTTP method called, a new instance of my service is created, but in my module, his is a singleton.

It's normal?

For example:

  1. first call "post" -> the instance of my service is same
  2. second call "post" -> the instance of my service is same
  3. third call "get" -> the instance of my service change

Snippet:

Module

object SellerModule extends TwitterModule {
  private val SELLER_REPOSITORY = "br.com.funus.core.seller.gateway.SellerRepositoryImpl"
  private val sellerRepositoryClass: Class[_ <: SellerRepository] = getClass.getClassLoader.loadClass(SELLER_REPOSITORY).asSubclass(classOf[SellerRepository])

  private val SELLER_REGISTER = "br.com.funus.core.seller.interactor.SellerRegisterImpl"
  private val sellerRegisterClass: Class[_ <: SellerRegister] = getClass.getClassLoader.loadClass(SELLER_REGISTER).asSubclass(classOf[SellerRegister])

  private val SELLER_SERVICE = "br.com.funus.core.seller.service.SellerServiceImpl"
  private val sellerServiceClass: Class[_ <: SellerService] = getClass.getClassLoader.loadClass(SELLER_SERVICE).asSubclass(classOf[SellerService])

  @Singleton
  @Provides
  def sellerRepository: SellerRepository = {
    sellerRepositoryClass.newInstance
  }

  @Singleton
  @Provides
  def sellerRegister: SellerRegister = {
    val constructor = sellerRegisterClass.getConstructors()(0)
    constructor.newInstance(sellerRepository).asInstanceOf[SellerRegister]
  }

  @Singleton
  @Provides
  def sellerService: SellerService = {
    val constructor = sellerServiceClass.getConstructors()(0)
    constructor.newInstance(sellerRepository, sellerRegister).asInstanceOf[SellerService]
  }
}

Controller

@Singleton
class SellerController @Inject()(
  sellerService: SellerService
) extends Controller {

  get("/v1/sellers") { request: Request =>
    val f: Future[Option[List[Seller]]] = sellerService.findAll
    f map { listModel =>
      listModel.get
    }
  }

  get("/v1/sellers/:id") { request: Request =>
    val id = request.params("id")
    val f: Future[Option[Seller]] = sellerService.findById(id.toInt)
    f map { rmModel =>
      rmModel.get
    }
  }

  post("/v1/sellers") { json: SellerJson =>
    val inModel = Some(new SellerRegisterIM(json.name, Some(json.birthDate), Some(json.documents)))
    val f: Future[SellerRegisterRM] = sellerService.register(inModel)
    f map { rmModel =>
      response
        .created()
        .location(rmModel.id.get)
    }
  }
}
@scosenza

This comment has been minimized.

Contributor

scosenza commented Aug 28, 2015

Your usage of @singleton on your SellerService provider is correct, and there should only be one instance of SellerService created.

A couple questions:

  1. Why are you using reflection to create SellerRepository, SellerRegister, and SellerService?
  2. Can I see what the class declaration of SellerService looks like?
  3. Can I see what your server looks like?
@sandokandias

This comment has been minimized.

sandokandias commented Aug 28, 2015

@scosenza.

  1. Because my implementations are protected and only traits are public.
  2. SellerService: ok
  3. ApiServer: ok

SellerService

trait SellerService {
  def register(inModel: Option[SellerRegisterIM]): Future[SellerRegisterRM]
  def findById(id: Int): Future[Option[Seller]]
  def findAll: Future[Option[List[Seller]]]
}

protected class SellerServiceImpl (
  sellerRepository: SellerRepository,
  sellerRegister: SellerRegister) extends SellerService {

    override def register(inModel: Option[SellerRegisterIM]): Future[SellerRegisterRM] = {
      Future(sellerRegister.perform(inModel))
    }

    override def findById(id: Int): Future[Option[Seller]] = {
      Future(sellerRepository.findById(id))
    }

    override def findAll: Future[Option[List[Seller]]] = {
      Future(sellerRepository.findAll)
    }
}

ApiServer

class ApiServer extends HttpServer {

  override val modules = Seq(SellerModule)

  override def configureHttp(router: HttpRouter): Unit = {
      router
      .filter[LoggingMDCFilter[Request, Response]]
      .filter[TraceIdMDCFilter[Request, Response]]
      .filter[CommonFilters]
      .add[SellerController]
  }
}
object ApiServerMain extends ApiServer
@sandokandias

This comment has been minimized.

sandokandias commented Aug 28, 2015

@scosenza, sorry, but the Repository change, not Service.

Logging

2015-08-28 12:36:11,260 INF c345f5f7361714f0          SellerServiceImpl         SellerServiceImpl -> br.com.funus.core.seller.service.SellerServiceImpl@20c67bd7
2015-08-28 12:36:11,271 INF c345f5f7361714f0          SellerRepositoryImpl      SellerRepositoryImpl.add -> br.com.funus.core.seller.gateway.SellerRepositoryImpl@5fe96359
2015-08-28 12:36:11,333 INF c345f5f7361714f0          AccessLoggingFilter       127.0.0.1 - - [28/Aug/2015:15:36:11 +0000] "POST /v1/sellers HTTP/1.1" 201 - 385 "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36"
2015-08-28 12:36:37,443 INF ca6a3ef65b37c5cc          SellerServiceImpl         SellerServiceImpl -> br.com.funus.core.seller.service.SellerServiceImpl@20c67bd7
2015-08-28 12:36:37,443 INF ca6a3ef65b37c5cc          SellerRepositoryImpl      SellerRepositoryImpl.add -> br.com.funus.core.seller.gateway.SellerRepositoryImpl@5fe96359
2015-08-28 12:36:37,444 INF ca6a3ef65b37c5cc          AccessLoggingFilter       127.0.0.1 - - [28/Aug/2015:15:36:37 +0000] "POST /v1/sellers HTTP/1.1" 201 - 1 "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36"
2015-08-28 12:36:46,162 INF 529948c26a47157e          SellerServiceImpl         SellerServiceImpl -> br.com.funus.core.seller.service.SellerServiceImpl@20c67bd7
2015-08-28 12:36:46,163 INF 529948c26a47157e          SellerRepositoryImpl      SellerRepositoryImpl.findAll -> br.com.funus.core.seller.gateway.SellerRepositoryImpl@5e253d35
2015-08-28 12:36:46,179 INF 529948c26a47157e          AccessLoggingFilter       127.0.0.1 - - [28/Aug/2015:15:36:46 +0000] "GET /v1/sellers HTTP/1.1" 200 2 17 "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36" 
@scosenza

This comment has been minimized.

Contributor

scosenza commented Aug 28, 2015

You're getting multiple instance of repository because you're calling the "sellerRepository" method from your other provider methods. Instead you need to pass in dependencies as method arguments: https://github.com/google/guice/wiki/ProvidesMethods

You have 2 options for your module: @Inject and @Provider. @Inject is preferred for classes you control

@Singleton
protected class SellerServiceImpl @Inject()(
  sellerRepository: SellerRepository,
  sellerRegister: SellerRegister) extends SellerService
@Singleton
protected class SellerRegisterImpl @Inject()(
  sellerRepository: SellerRepository) extends SellerRegister
@Singleton
protected class SellerRepositoryImpl extends SellerRepository
object SellerModule extends TwitterModule {
  def configure {
    bind[SellerService].to[SellerServiceImpl]
    bind[SellerRegister].to[SellerRegisterImpl]
    bind[SellerRepository].to[SellerRepositoryImpl]
  }
}
object SellerModule extends TwitterModule {
  @Singleton
  @Provides
  def sellerRepository: SellerRepository = {
    new SellerRepositoryImpl
  }

  @Singleton
  @Provides
  def sellerRegiste(sellerRepository: SellerRepository): SellerRegister = {
    new SellerRegister(sellerRepository)
  }

  @Singleton
  @Provides
  def sellerService(sellerRepository: SellerRepository, sellerRegister: SellerRegister): SellerService = {
    new SellerService(sellerRepository, sellerRegister)
  }
}
@sandokandias

This comment has been minimized.

sandokandias commented Aug 28, 2015

@scosenza, thks! It's fine now.

Sorry for open issue.

@scosenza

This comment has been minimized.

Contributor

scosenza commented Aug 28, 2015

No need to apologize! Please let us know if you have any further questions or issues.

@scosenza scosenza closed this Aug 28, 2015

@sandokandias

This comment has been minimized.

sandokandias commented Aug 28, 2015

@scosenza , thks for help!
I am really very satisfied with finatra.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment