Bean 定义 DSL
Spring 框架支持使用 lambda 以函数式方式注册 Bean,作为 XML 或 Java 配置(@Configuration
和 @Bean
)的替代方案。简而言之,它允许您使用充当FactoryBean
的 lambda 来注册 Bean。这种机制非常高效,因为它不需要任何反射或 CGLIB 代理。
例如,在 Java 中,您可以编写以下代码
class Foo {}
class Bar {
private final Foo foo;
public Bar(Foo foo) {
this.foo = foo;
}
}
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(Foo.class);
context.registerBean(Bar.class, () -> new Bar(context.getBean(Foo.class)));
在 Kotlin 中,使用具现化类型参数和GenericApplicationContext
Kotlin 扩展,您可以编写以下代码
class Foo
class Bar(private val foo: Foo)
val context = GenericApplicationContext().apply {
registerBean<Foo>()
registerBean { Bar(it.getBean()) }
}
当类Bar
只有一个构造函数时,您甚至可以只指定 Bean 类,构造函数参数将按类型自动装配
val context = GenericApplicationContext().apply {
registerBean<Foo>()
registerBean<Bar>()
}
为了允许更声明式的方法和更简洁的语法,Spring 框架提供了一个Kotlin Bean 定义 DSL它通过简洁的声明式 API 声明一个ApplicationContextInitializer
,允许您处理配置文件和Environment
以自定义 Bean 的注册方式。
在以下示例中,请注意
-
类型推断通常允许避免为 Bean 引用(如
ref("bazBean")
)指定类型 -
可以使用 Kotlin 顶级函数通过可调用引用(如本例中的
bean(::myRouter)
)来声明 Bean -
在指定
bean<Bar>()
或bean(::myRouter)
时,参数将按类型自动装配 -
只有在激活
foobar
配置文件时才会注册FooBar
Bean
class Foo
class Bar(private val foo: Foo)
class Baz(var message: String = "")
class FooBar(private val baz: Baz)
val myBeans = beans {
bean<Foo>()
bean<Bar>()
bean("bazBean") {
Baz().apply {
message = "Hello world"
}
}
profile("foobar") {
bean { FooBar(ref("bazBean")) }
}
bean(::myRouter)
}
fun myRouter(foo: Foo, bar: Bar, baz: Baz) = router {
// ...
}
此 DSL 是程序式的,这意味着它允许通过if 表达式、for 循环或任何其他 Kotlin 结构来进行 Bean 的自定义注册逻辑。 |
然后,您可以使用此beans()
函数在应用程序上下文中注册 Bean,如下例所示
val context = GenericApplicationContext().apply {
myBeans.initialize(this)
refresh()
}
Spring Boot 基于 JavaConfig,并且尚未提供对函数式 Bean 定义的特定支持,但您可以通过 Spring Boot 的ApplicationContextInitializer 支持来试验性地使用函数式 Bean 定义。有关更多详细信息和最新信息,请参阅此 Stack Overflow 答案。另请参阅在Spring Fu 孵化器中开发的实验性 Kofu DSL。 |