日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Play! Framework 系列(三):依赖注入

發(fā)布時(shí)間:2025/1/21 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Play! Framework 系列(三):依赖注入 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Play! Framework 系列(二)中我們介紹了 Play 的項(xiàng)目結(jié)構(gòu)。在日常處理業(yè)務(wù)邏輯的時(shí)候,我們都會(huì)用到依賴注入,本文將介紹一下 Play! 中的依賴注入以及如何合理地去使用她。

為什么要使用「依賴注入」

在許多 Java 框架中,「依賴注入」早已不是一個(gè)陌生的技術(shù),Play 框架從 2.4 開始推薦使用?Guice?來作為依賴注入。

采用依賴注入最大的好處就是為了「解耦」,舉個(gè)栗子:

上一篇文章的例子中,我們實(shí)現(xiàn)了一個(gè) EmployeeService 用來對(duì)公司的員工進(jìn)行操作:

1

2

3

4

5

6

7

package services

import models._

classEmployeeSerivce{

...

}

在之前的實(shí)現(xiàn)中,我們沒有加入數(shù)據(jù)庫的操作,那么現(xiàn)在我們想要引入一個(gè)數(shù)據(jù)庫連接的類:DatabaseAccessService 來對(duì)數(shù)據(jù)庫進(jìn)行連接以便我們對(duì)相應(yīng)的數(shù)據(jù)庫表進(jìn)行操作,則:

新建一個(gè)數(shù)據(jù)庫連接操作的 Service

1

2

3

package services

classDatabaseAccessService{}

EmployeeSerivce 需要依賴 DatabaseAccessService

1

2

3

4

5

6

7

package services

import models._

classEmployeeSerivce(db: DBService){

...

}

好了,現(xiàn)在我們需要在 EmployeeController 中使用 EmployeeSerivce,如果不采用依賴注入,則:

1

2

3

4

5

6

7

8

9

10

11

classEmployeeController@Inject() (

cc: ControllerComponents

) extends AbstractController(cc) {

val db = newDatabaseAccessService()

val employeeSerivce = newEmployeeSerivce(db)

def employeeList = Action { implicit request: Request[AnyContent] =>

val employees = employeeSerivce.getEmployees()

Ok(views.html.employeeList(employees))

}

}

可以看到,為了實(shí)例化 EmployeeSerivceDatabaseAccessService 也需要實(shí)例化,如果隨著需求的增加,EmployeeSerivce 所需要依賴的東西增加,那么我們每次實(shí)例化 EmployeeSerivce 的時(shí)候都需要將她的依賴也實(shí)例化一遍,而且她的依賴也有可能會(huì)依賴其他東西,這樣就使得我們的代碼變得非常冗余,也極難維護(hù)。

為了解決這一問題,我們引入了依賴注入,Play支持兩種方式的依賴注入,分別是:「運(yùn)行時(shí)依賴注入」以及「編譯時(shí)依賴注入」,接下來我們就通過這兩種依賴注入來解決我們上面提出的問題。

運(yùn)行時(shí)依賴注入(runtime dependency

Play 的運(yùn)行時(shí)依賴注入默認(rèn)采用?Guice,關(guān)于 Guice,我們后面的文章當(dāng)中會(huì)介紹,這里只需要知道她。為了支持 Guice 以及其他的運(yùn)行時(shí)依賴注入框架,Play 提供了大量的內(nèi)置組件。詳見?play.api.inject

那么在 Play 中我們將如何使用這種依賴注入呢?回到我們文章剛開始講的那個(gè)栗子中,現(xiàn)在我們通過依賴注入的方式來重新組織我們的代碼:

首先 EmployeeSerivce 需要依賴 DatabaseAccessService,這里其實(shí)就存在一個(gè)「依賴注入」,那我們這樣去實(shí)現(xiàn):

1

2

3

4

5

6

7

8

package services

import models._

import javax.inject._

classEmployeeSerivce@Inject() (db: DBService){

...

}

在上面的代碼中,我們引入了?import javax.inject._,并且可以看到多了一個(gè)?@Inject()?注解,我們實(shí)現(xiàn)運(yùn)行時(shí)依賴注入就采用該注解。

那么在 EmployeeController 中,我們的代碼就變成了:

1

2

3

4

5

6

7

8

9

classEmployeeController@Inject() (

employeeSerivce: EmployeeSerivce,

cc: ControllerComponents

) extends AbstractController(cc) {

def employeeList = Action { implicit request: Request[AnyContent] =>

val employees = employeeSerivce.getEmployees()

Ok(views.html.employeeList(employees))

}

}

可以看到我們不需要再去寫那么多的實(shí)例了,我們只要在需要某種依賴的地方聲明一下我們需要什么樣的依賴, Play 在運(yùn)行時(shí)就會(huì)將我們需要的依賴注入到相應(yīng)的組件中去。

tip@Inject?必須放在類名的后面,構(gòu)造參數(shù)的前面。

「運(yùn)行時(shí)依賴注入」,顧名思義就是在程序運(yùn)行的時(shí)候進(jìn)行依賴注入,但是她不能在編譯時(shí)進(jìn)行校驗(yàn),為了能讓程序在編譯時(shí)就能實(shí)現(xiàn)對(duì)依賴注入的校驗(yàn), Play支持了「編譯時(shí)依賴注入」。

編譯時(shí)依賴注入(compile time dependency injection

為了實(shí)現(xiàn)編譯時(shí)依賴注入,我們需要知道 Play 提供的一個(gè)特質(zhì):ApplicationLoader,該特質(zhì)中的 load 方法將會(huì)在程序啟動(dòng)的時(shí)候加載我們的應(yīng)用程序,在這個(gè)過程中,Play 框架本身以及我們自己的程序代碼所依賴的東西都會(huì)被實(shí)例化。

默認(rèn)情況下,Play 提供了一個(gè) Guice 模塊,該模塊下的 GuiceApplicationBuilder 會(huì)根據(jù) Play 框架給定的 context 去將該程序所依賴的所有組件聯(lián)系在一起。

如果我們要自定義 ApplicationLoader,我們也需要一個(gè)像 GuiceApplicationBuilder 的東西,好在 Play 提供了這么一個(gè)東西,那就是:BuiltInComponentsFromContext,我們可以通過繼承這個(gè)類來實(shí)現(xiàn)我們自己的 ApplicationLoader

接下來我們通過相應(yīng)的代碼來作進(jìn)一步的解釋:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

import controllers._

import play.api._

import play.api.routing.Router

import services._

import router.Routes

//自定義 ApplicationLoader

classMyApplicationLoaderextendsApplicationLoader {

def load(context: Context): Application = {

newMyComponents(context).application

}

}

classMyComponents(context: Context)

extendsBuiltInComponentsFromContext(context)

with play.filters.HttpFiltersComponents {

lazyval databaseAccessService = newDatabaseAccessService

lazyval employeeSerivce = newEmployeeSerivce(databaseAccessService)

lazyval employeeController = newEmployeeController(employeeSerivce, controllerComponents)

lazyval router: Router = newRoutes(httpErrorHandler, employeeController)

}

我們通過繼承 BuiltInComponentsFromContext 使得程序能夠根據(jù) Play 所提供的 context 來加載 Play 框架本身所需要的一些組件。

那么回到我們的「編譯時(shí)的依賴注入」中來,可以看到在 class MyComponents 中,我們將所有的 service 都實(shí)例化了,并且將這些實(shí)例注入到相應(yīng)的依賴她們的模塊中:

1

2

3

4

5

6

7

8

//將兩個(gè) service 實(shí)例化

lazyval databaseAccessService = newDatabaseAccessService

//EmployeeSerivce 依賴 DatabaseAccessService,將實(shí)例 databaseAccessService 注入其中

lazyval employeeSerivce = newEmployeeSerivce(databaseAccessService)

// employeeSerivce 注入到 employeeController

lazyval employeeController = newEmployeeController(employeeSerivce, controllerComponents)

使用 BuiltInComponentsFromContext 時(shí),我們需要自己實(shí)現(xiàn)一下 router

1

lazyval router: Router = newRoutes(httpErrorHandler, employeeController)

tip:需要注意的是,如果我們實(shí)現(xiàn)了自己的 ApplicationLoader,我們需要在?application.conf?文件中聲明一下:

1

play.application.loader = MyApplicationLoader

通過自定義 ApplicationLoader 我們就實(shí)現(xiàn)了編譯時(shí)期的依賴注入,那么 EmployeeSerivce 就變成了:

1

2

3

4

5

6

7

package services

import models._

classEmployeeSerivce (db: DBService){

...

}

可以看到,這里就省去了?@Inject()?注解。

同樣的,對(duì)于 EmployeeController

1

2

3

4

5

6

7

8

9

10

11

12

13

14

package controllers

import play.api._

import play.api.mvc._

import models._

import services._

// 沒有了 @Inject() 注解

classEmployeeController (

employeeSerivce: EmployeeSerivce,

cc: ControllerComponents

) extends AbstractController(cc) {

...

}

通過使用編譯時(shí)期的依賴注入,我們只需要在將所有的依賴實(shí)例化一次就夠了,并且使用這種方式,我們能夠在編譯時(shí)期就能發(fā)現(xiàn)程序的一些異常。同樣的,使用該方法也會(huì)有一些問題,就是我們需要寫許多樣板代碼。另外本文的編譯時(shí)期的依賴注入完全是自己手動(dòng)注入的,看上去也比較繁瑣,不是那么直觀,如果要使用更優(yōu)雅的方式,我們可以使用?macwire,這個(gè)我們?cè)诤竺娴奈恼轮袝?huì)詳細(xì)講解。

結(jié)語

本文簡(jiǎn)單介紹了一下 Play 支持的兩種依賴注入的模式,文中提到的一些第三方依賴注入的框架我們會(huì)在后面的文章中詳細(xì)介紹。本文的例子請(qǐng)戳源碼鏈接

本文轉(zhuǎn)載自:https://scala.cool/2017/11/play-3/

總結(jié)

以上是生活随笔為你收集整理的Play! Framework 系列(三):依赖注入的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。