先行一步
VMware 提供培訓和認證,助您快速發展。
瞭解更多去年十月,我在 SpringOne2GX 大會上向全世界介紹了 Spring Scala 專案。自那以後,我還在 Devoxx 大會上展示了這個專案。在這篇部落格文章中,我將進一步詳細介紹這個專案以及如何在您的 Scala 專案中使用它。
顯然,今天您可以在 Scala 中使用(Java)Spring 框架,無需 Spring Scala。但在某些地方這樣做會很彆扭。就像任何程式語言一樣,Scala 有自己獨特的方式做事,在 Scala 中使用一個純 Java 框架如 Spring 會感覺“太 Java 味兒”了。Spring Scala 試圖透過讓 Spring 成為 Scala 語言的一等公民來解決這個問題。
Spring Scala 正在進行中。在這篇文章的其餘部分,我將重點介紹目前已經實現的功能。然而,我們預計在接下來的幾個月會新增許多額外功能,希望是透過您提供的反饋來實現。因此,如果您對某個功能有想法,認為它能讓在 Scala 中使用 Spring 更愉快,請透過提交 JIRA 問題 或留言來告訴我們。
在 Spring XML 應用上下文中裝配 Scala Bean 最簡單且首選的方式是使用建構函式注入。例如,假設我們有以下 Scala 類:
class Person(val firstName: String, val lastName: String)
您可以使用 c 名稱空間如下裝配這個類:
<bean id="person" class="Person" c:firstName="John" c:lastName="Doe"/>
請注意,透過將建構函式注入與 val
結合使用,我們還使得 Person
類不可變。函式式語言(如 Scala)鼓勵使用不可變資料結構。因此,在 Scala 中使用 Spring 時首選建構函式注入。另外請注意,建構函式注入是開箱即用的;它無需在類路徑中包含 Spring Scala jar 包即可工作。
說到 setter 注入,事情就變得有點複雜了。預設情況下,Scala 類不遵循 JavaBeans 屬性契約(例如 String getFoo()
和 void setFoo(String)
)。相反,Scala 有自己的屬性契約:“getter”不以 get
為字首,而是使用欄位名作為方法名(例如 foo: String
)。Scala 的 setter 則在欄位名後加上 =
(例如 foo
=(String): Unit
)。
為了解決這個問題,您可以指示 Scala 編譯器使用 @scala.reflect.BeanProperty
註解生成 JavaBeans getter 和 setter;或者您可以在類路徑中新增 Spring Scala 以啟用對 Scala setter 的支援。
使用 @BeanProperty
就像用它註解一個 var
一樣簡單:
class Person(@BeanProperty var firstName: String, @BeanProperty var lastName: String)
這將導致為該類建立 JavaBean 風格的 setter,以便您可以非常簡單地在 XML 中裝配它:
<bean id="constructor" class="Person" p:firstName="John" p:lastName="Doe"/>
作為使用此註解的替代方案,從版本 3.2 開始,Spring 支援使用 BeanInfoFactory
策略介面來支援任意的 getter 和 setter。Spring Scala 專案包含此介面的一個實現,該實現支援 Scala 的 getter 和 setter。Spring 會自動檢測到此實現,無需額外的配置。
實際上,這意味著將 Spring Scala jar 包放在類路徑中將啟用對 Scala 屬性的支援,並且您可以使用上面的 XML 配置來裝配 Person
類,而無需新增 @BeanProperty
註解。
有關在 Spring XML 中裝配 Scala Bean 的更多資訊,請參閱 Spring Scala 文件 Wiki 的相關章節。另請參閱有關在 Spring XML 中裝配 Scala 集合的章節。
除了在 XML 中定義 Bean,Spring Scala 還提供了一種替代方案,它使用 Scala 類而不是 XML 檔案來配置您的 Spring Bean。這種方法類似於在 Spring Java 中使用 @Configuration,不同之處在於它是基於函式而不是註解。
要建立一個函式式 Spring 配置,您只需在配置類中混入 FunctionalConfiguration
特質即可。Bean 透過呼叫該特質上的 bean
方法並傳入一個建立 Bean 的函式來定義。
給定上面展示的 Person
類,我們可以在函式式配置中如下裝配它:
class PersonConfiguration extends FunctionalConfiguration {
bean() {
new Person("John", "Doe")
}
}
當然,您也可以將 Bean 註冊到特定的名稱下,提供別名,或設定作用域:
class PersonConfiguration extends FunctionalConfiguration {
bean("john", aliases = Seq("doe"), scope = BeanDefinition.SCOPE_PROTOTYPE) {
new Person("John", "Doe")
}
}
然後,您可以使用此配置類建立 Spring 應用上下文:
object PersonConfigurationDriver extends App {
val applicationContext = new FunctionalConfigApplicationContext(classOf[PersonConfiguration])
val john = applicationContext.getBean(classOf[Person])
println(john.firstName)
}
有關函式式 Bean 配置的更多資訊,包括強型別 Bean 引用、如何匯入 XML 檔案和 @Configuration 類以及如何在 profile 中包裝 Bean 定義的章節,請參閱 Spring Scala 文件 Wiki 的相關章節。
Spring 的模板是實用的工具類,有助於一般的資料訪問或資源處理。Spring Scala 包含一些包裝器,可將(Java)模板適配得更適合 Scala 使用。總的來說,這些 Scala 模板包裝器在使用時相比 Java 版本有三個改進:
null
的地方使用 Option
透過這三個改進,您可以如下使用 JmsTemplate
:
val connectionFactory : ConnectionFactory = ...
val template = new JmsTemplate(connectionFactory)
template.send("queue") {
session: Session => session.createTextMessage("Hello World")
}
template.receive("queue") match {
case Some(textMessage: TextMessage) => println(textMessage.getText)
case _ => println("No text message received")
}
通常,模板包裝器的 Scala 版本與其 Java 對應版本位於相同的包中,只是中間多了一個 scala
包。例如,JmsTemplate
的 Scala 版本位於 org.springframework.scala.jms.core
。截至撰寫本文時,存在以下適合 Scala 的模板:
有關在 Scala 中使用 Spring 模板的更多資訊,請參閱 Spring Scala 文件 Wiki 的相關章節。
<repositories>
<repository>
<id>milestone.repo.springsource.org</id>
<name>repo.springsource.org-milestone</name>
<url>https://repo.springsource.org/libs-milestone</url>
</repository>
</repositories>
<dependency>
<groupId>org.springframework.scala</groupId>
<artifactId>spring-scala</artifactId>
<version>1.0.0.M2</version>
</dependency>
專案本身可在 GitHub 獲取。如果您想貢獻,可以透過為功能請求提交 JIRA 或在 GitHub 提交 pull request 來進行。
注意:截至 2013-04-02,已經發布了一個新的里程碑版本。請閱讀論壇公告。