领先一步
VMware 提供培训和认证,以助您快速提升技能。
了解更多去年 10 月,在 SpringOne2GX 上,我向世界介绍了 Spring Scala 项目。从那时起,我还曾在 Devoxx 上介绍过这个项目。在这篇博文中,我想进一步详细介绍这个项目以及如何在 Scala 项目中使用它。
显然,您今天可以在没有 Spring Scala 的情况下在 Scala 中使用(Java)Spring 框架。但这样做在某些地方会很笨拙。就像任何编程语言一样,Scala 也有自己不同的做事方式,在 Scala 中使用纯 Java 框架(如 Spring)只会让人感觉“太 Java 化了”。Spring Scala 试图通过使 Spring 成为 Scala 语言的一等公民来解决这个问题。
Spring Scala 仍在开发中。在本文的其余部分,我将重点介绍当前已实现的功能。但是,我们预计未来几个月将添加许多其他功能,希望通过您提供的反馈来实现。因此,如果您有任何想法可以使 Spring 在 Scala 中使用起来更愉快,请通过提交 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 类以及如何在配置文件中包装 Bean 定义的部分,请参阅 Spring Scala 文档 wiki 的 相关部分。
Spring 的模板是有用的实用程序类,它们有助于任何类型的数据访问或资源处理。Spring Scala 包含适配(Java)模板以使其更适合 Scala 的包装器。通常,与在 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 上提交拉取请求来做到这一点。
注意,截至 2013 年 4 月 2 日,已发布了一个新的里程碑版本。阅读 论坛公告。