領先一步
VMware 提供訓練和認證,以加速您的進展。
了解更多去年十月,在 SpringOne2GX 大會上,我向世界介紹了 Spring Scala 專案。從那時起,我也在 Devoxx 大會上展示了這個專案。在這篇部落格文章中,我想要更詳細地介紹這個專案,以及如何在您的 Scala 專案中使用它。
顯然地,即使沒有 Spring Scala,您今天仍然可以在 Scala 中使用 (Java) Spring Framework。但這樣做在某些地方會顯得笨拙。就像任何程式語言一樣,Scala 有自己獨特的方式來做事,而在 Scala 中使用像 Spring 這樣純粹的 Java 框架會感覺「太 Java 風格」。Spring Scala 試圖透過使 Spring 成為 Scala 語言的一等公民來解決這個問題。
Spring Scala 仍在開發中。在這篇文章的其餘部分,我將重點介紹目前已實作的功能。然而,我們預期在未來幾個月內會新增更多功能,希望能透過您提供的回饋來實現。因此,如果您對某個功能有想法,可以讓在 Scala 中使用 Spring 更加愉快,請透過提交 JIRA issue 或留言告訴我們。
在 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 Collections 的章節。
除了在 XML 中定義 bean 之外,Spring Scala 還提供另一種替代方案,使用 Scala 類別而不是 XML 檔案來配置您的 Spring bean。這種方法類似於在 Spring Java 中使用 @Configuration,不同之處在於它是基於函數而不是註解。
若要建立函數式 Spring 設定,您只需將 FunctionalConfiguration
trait 混入您的設定類別中。Bean 是透過在 trait 上呼叫 bean
方法並傳入一個建立 bean 的函數來定義的。
假設有上面顯示的 Person
類別,我們可以像這樣在函數式設定中配置它
class PersonConfiguration extends FunctionalConfiguration {
bean() {
new Person("John", "Doe")
}
}
當然,您也可以使用特定名稱註冊 bean、提供別名或設定 scope
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 的 templates 是很有用的工具類別,有助於任何形式的資料存取或資源處理。Spring Scala 包含 wrappers,可以調整 (Java) templates 以更符合 Scala 的使用習慣。一般來說,這些 Scala template wrappers 在 Scala 語言中使用時,相較於 Java 版本有三個改進
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")
}
一般來說,template wrappers 的 Scala 版本與它們的 Java 對應版本位於相同的套件中,只是中間有一個 scala
套件。因此,例如 JmsTemplate
的 Scala 版本位於 org.springframework.scala.jms.core
中。在撰寫這篇文章時,存在以下 Scala 友善的 templates
有關在 Scala 中使用 Spring Templates 的更多資訊,請參閱 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 issue 來提出功能請求,或是在 GitHub 上留下 pull request。
請注意,截至 2013-04-02,已發佈新的里程碑版本。請閱讀論壇公告。