Play Framework 2.5:如何在Trait中正确注入DBApi及DI适配疑问
Hey there! Let's break down your two questions about migrating your DataSource trait to use Play 2.5's dependency injection system.
1. How to Properly Inject DBApi in a Trait
Play 2.5 phased out static helpers like Play.current and DB in favor of dependency injection (DI), so we need to adjust your trait to pull DBApi via DI instead. There are two clean, idiomatic approaches to do this:
Option 1: Field Injection with @Inject
You can annotate a protected field in your trait with @Inject to let Play's DI container populate it. Just remember: traits can't be instantiated directly, so you'll need a concrete class that inherits the trait and is managed by the DI system.
import play.api.db.DBApi import javax.inject.Inject trait DataSource { // Mark the field as @Inject; protected so subclasses can access it @Inject protected var dbApi: DBApi = _ def dataSource = dbApi.database("default").dataSource }
Then, in a concrete class (like a service or controller) that uses this trait:
import javax.inject.Inject // This class is DI-managed thanks to the @Inject constructor class UserService @Inject()() extends DataSource { // You can now use dataSource here—dbApi will be injected automatically def fetchUsers() = { val connection = dataSource.getConnection() // ... your database logic here } }
Option 2: Constructor Injection (Recommended)
For better immutability and safety (no risk of uninitialized null fields), define an abstract method in the trait for DBApi, then have the concrete class inject it via its constructor and implement the abstract method.
import play.api.db.DBApi trait DataSource { // Abstract method to expose the required dependency protected def dbApi: DBApi def dataSource = dbApi.database("default").dataSource }
Then in your concrete class:
import javax.inject.Inject // Inject DBApi via constructor, then pass it to the trait class OrderService @Inject()(override protected val dbApi: DBApi) extends DataSource { // dataSource is ready to use, powered by the injected dbApi }
2. Do Traits Support Dependency Injection?
Short answer: Yes, but with a small caveat. Traits themselves can't be directly instantiated or managed by Play's DI container—DI works with concrete classes. However, you absolutely can use dependency injection in traits by:
- Defining abstract dependencies (like the
dbApimethod in Option 2) that concrete classes provide via their DI-injected constructors. - Using field injection (Option 1) where the DI container populates the trait's field when it instantiates the concrete subclass.
The critical thing is that the concrete class inheriting the trait must be a DI-managed class (either with an @Inject constructor or registered in Play's DI config). The trait's dependencies will be resolved automatically when the subclass is created by the DI container.
Pro Tip
Constructor injection is almost always preferred over field injection. It ensures all dependencies are available the moment the class is instantiated, eliminating null pointer risks from uninitialized fields.
内容的提问来源于stack exchange,提问作者med10

