Bean Definition DSL
Spring Framework 支援以函數式方式註冊 bean,透過使用 lambda 作為 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 Framework 提供了 Kotlin bean 定義 DSL。它透過簡潔的宣告式 API 宣告 ApplicationContextInitializer
,讓您可以處理 profile 和 Environment
以自訂 bean 的註冊方式。
在以下範例中,請注意
-
類型推斷通常允許避免指定 bean 參考的類型,例如
ref("bazBean")
-
可以使用 Kotlin 頂層函數來宣告 bean,在此範例中使用可呼叫參考,例如
bean(::myRouter)
-
當指定
bean<Bar>()
或bean(::myRouter)
時,參數會依類型自動裝配 -
FooBar
bean 僅在foobar
profile 啟用時才會註冊
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()
函數在應用程式 Context 中註冊 bean
val context = GenericApplicationContext().apply {
myBeans.initialize(this)
refresh()
}
Spring Boot 基於 JavaConfig,並且尚未提供對函數式 bean 定義的特定支援,但您可以透過 Spring Boot 的 ApplicationContextInitializer 支援實驗性地使用函數式 bean 定義。如需更多詳細資訊和最新資訊,請參閱此 Stack Overflow 回答。另請參閱在 Spring Fu incubator 中開發的實驗性 Kofu DSL。 |