2015-07-10 70 views
7

我期待在從播放郵件的鱗屑代碼示例:https://github.com/playframework/play-mailer斯卡拉(播放的2.4.x)如何調用與@Inject()註釋類

它去基本上是這樣的:

class MyComponent @Inject() (mailerClient: MailerClient) { 
    ... 
} 

足夠簡單,它編譯沒有符合

然後我試着然而,「呼叫」,並似乎沒有被滿足的編譯器或獲取mailerClient的工作實例的方式。

object AnObject { 
    val mailer = new MyComponent 
    def sendEmail = mailer.doStuff 
} 

[info] Compiling 1 Scala source to ... 
[error] /SomeOne/SomePath/SomeFile.scala:30: not enough arguments for constructor MyComponent: (mailerClient: play.api.libs.mailer.MailerClient) MyComponent. 
[error] Unspecified value parameter mailerClient. 
[error] val mailer = new MyComponent 
[error]    ^
[error] one error found 
[error] (compile:compileIncremental) Compilation failed 

不過,我覺得我可能已經得到了接近得益於此:

How does @Inject in Scala work

這表明以下語法可以通過從構造的@Inject,並把它放在一個領域的工作。

@Inject var mailerClient: MailerClient = null 

但是,當我們嘗試運行任何需要該引用的東西時,我們仍然得到空值。

我讀的一切,我可以找到關於@Inject

([警示] [咆哮]我不是這個確切原因的編譯器魔術這樣的風扇 - 巫術是美好的,直到它[/ rant] [/ warning])

但我真正想知道的是如何正確,安全和有效地使用它。

+0

僅供參考 - 這可能有助於那些只是爲了讓電子郵件工作... https://github.com/playframework/play-mailer/blob/master/src/test/scala/play/api/libs/mailer /MailerPluginSpec.scala – Techmag

回答

0

這不是一個scala問題,而是一個DI問題。您應該閱讀一些guice文檔。

在Play 2.4.x中,您需要使用依賴注入(https://www.playframework.com/documentation/2.4.x/ScalaDependencyInjection) 來實現您的目標。

你AnObject應該是:

@Singleton class AnObject @Inject()(mailer:MyComponent){ 
def sendEmail = mailer.doStuff 
} 
+1

嗯:Guice的目標是使開發和調試更容易,更快,而不是更難和更慢。就此而言,吉斯避開了驚喜和魔法。 ??? – Techmag

+0

工廠和單身人士現在看起來真的很棒。 – Techmag

+1

仍然沒有解決原來的問題 - 我們只是把它放到另一個類中 - 我現在要如何調用(使用)這個AnObject,編譯器需要一個AnObject的郵件參數。告訴我如何從一個物體中使用它 - 我知道這是與Guice試圖做的對比 - 但至少我可以從那裏拿走它。 – Techmag

10

既然你關閉你的問題對原GitHub庫,我不知道這個答案仍然是必要的,但因爲你沒有完全瞭解使用的DI框架,我發現學習這個技能非常重要,我會試着在這裏解釋它並列出一些好處。

首先,你實例化你的實例的方式不會給DI框架注入依賴的機會。由於new是語言關鍵字,因此DI不會產生干擾,您的類所需的依賴關係無法注入。它是如何完成的是通過構造函數或字段注入。我將主要關注構造器注入,因爲這是scala世界中的「標準」。

如果使用@Injected註釋指定構造函數參數,則基本上是告訴DI框架從容器中解析此依賴項。 DI框架進入並在其容器內查找該對象的條目。如果它不存在,它將創建它(並解析其在進程中的依賴關係),並且如果它的註釋使用@Singleton也保存此實例以供將來使用。大多數DI框架要求您在大多數情況下指定一個啓動類,但是因爲您正在使用Play!這是沒有必要的框架。當你想使用一個特定的模塊控制器裏面,你可以這樣做:

import javax.inject.Inject 

import play.api.mvc.Controller 

class Test @Inject() (val dependency: FooClass) extends Controller { 
    ... 
} 

在這種情況下FooClass是要注入到控制器中依賴的類名。假設FooClass將Play的Application作爲依賴項注入,因爲Play提供了一對預先綁定的預設,例如Application,還有ActorSystem

這是可能的,因爲玩!框架使用DependencyInjectedRoutes。如果要在控制器之外創建一個Actor,則需要在模塊類中指定該角色,但在此​​和link中解釋了這一點。

在你的控制器裏面還有一個使用Traits的概念,然後再把這些特性和實現類連接起來,但我認爲這有點太複雜了。

如果你想要一些好處和更迭的故事的編寫應用這種方法,這裏是一個很好的資源:https://softwareengineering.stackexchange.com/a/19204/164366

如果你想要的東西,對這個概念閱讀:

我希望這可以解決問題!如果你有問題,請不要問!

+0

我完全理解DI-THAT的目的和要求不是問題 - 我已閱讀了大部分Guice文檔 - 包括與@Inject進程(及其所有相關選項)有關的所有內容,然而我仍然無法訪問「@ Injected」對象。我認爲Play有一些魔術可以讓控制器擁有可注入的構造函數。文檔中的某些內容暗示零參數構造函數是變幻莫測的,而@ @ Injected是由它調用的(或者反之亦然)。 – Techmag

+0

也許'@ Injected'對象只能在「對象內部」使用 - 但即使這是真的,那麼爲什麼每次嘗試在運行時使用字段注入都會導致空指針呢?我在Global.scala啓動(並綁定)了Guice,並且已經追蹤它以確保它實際上按照預期加載。所以這個問題(和我的原始問題)仍然存在。我想知道的僅僅是缺少一部分來訪問'@ Injected' Objects ... – Techmag

+1

這個dosn't回答這個問題,我有同樣的問題。如果在我想要使用該類時必須傳入對象,那麼在類構造函數中使用DI的意義是什麼 – Ir1sh

0

我遇到了同樣的問題。我想創建一個具有郵件功能的類或對象,然後當我想從任何控制器發送電子郵件時,我可以調用它。

我想你所問的等同於如何使用mailerclient外部播放框架。據我所知,你不能。即使你在app/controllers文件夾中創建了一個類,它只是一個普通的scala類,與play框架中的魔術無關。 @Inject僅適用於控制器或模塊。因爲如果你創建一個獨立的類,你必須在實例化時自己注入一些東西。除非您正在構建模塊或擴展控制器。你注意到AppController曾經是對象,現在它是一個類?當你使用它時,你不需要實例化。我相信框架通過配置(注入)來實例化它。所以如果你想達到最初的設計目標,你可以編寫一個模塊,發佈它,然後在所有的控制器中使用它;或者使用scala中的一些其他電子郵件庫來包裝電子郵件發送功能。

+0

因爲我很痛苦地發現真正的答案是Injected類只能通過一個Injected類來實例化(這就是它們一直表現出來的海龜的含義)。這不是真的,你需要在控制器中這樣做 - 它只是由於上述規則而出現。最早可以獲得「板載」的東西以前是GlobalSettings,它現在已經遷移到了'play.modules.enabled'配置項。你可以創建自己的Injectable類,但它們也必須通過另一個Injected類(該死的一堆烏龜)拾取。一位威士忌探戈Foxtrot的情況恕我直言:) – Techmag

+0

這就是我的意思是通過創建一個模塊。即使你可以用@inject創建一個類,如果它不是一個控制器或一個模塊,在你使用它的時候你仍然必須實例化,在這種情況下這是無奈的。 – yang

0

(我沒有足夠的信譽發表評論,所以張貼作爲一個答案)

發表@aparo答案應該被標記爲corect /認可的答案,因爲它確實解決問題。你說這不能解決原來的問題,因爲它會將依賴關係轉移到另一個類中,但這只是部分正確的,因爲其他類只需向您提供MyComponent而不是MailerClient。雖然依賴注入需要一直使用到最終控制器(在Play的情況下),但通常不需要注入更多的單個對象。

這個證明可以看出in a question I posted,因爲我在當時與你有相同的心態。在我的例子中,我的控制器只需要一個UserSearch依賴關係,依賴關係由guice處理,所以我不需要再次聲明它。

+0

我終於與DI達成了和平(或者至少是Guice in Play),而魔幻時刻正在接受爲了獲得一個Injected組件,首先你必須注入一個注入組件。問題是(我懷疑)超過一些人將會退出注射循環,並因此提出一個像我一樣的問題,永遠無法令人滿意地回答。 (所有試驗都會導致NULL激發文檔*似乎*的說法。)我計劃回來並記錄下*作爲幫助其他人阻止我循環的最長時間的答案...... – Techmag