对于最新的稳定版本,请使用 Spring Framework 7.0.6!spring-doc.cadn.net.cn

Bean 定义 DSL

Spring Framework 通过使用 lambda 表达式作为 XML 或 Java 配置(@Configuration@Bean)的替代方式,支持以功能化的方式注册 bean。简而言之,它允许你通过一个充当 FactoryBean 的 lambda 表达式来注册 bean。 此机制非常高效,因为它不需要任何反射或 CGLIB 代理。spring-doc.cadn.net.cn

在 Java 中,你可以编写如下代码:spring-doc.cadn.net.cn

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 中,使用 reified 类型参数和 GenericApplicationContext 个 Kotlin 扩展, 您可以编写以下内容:spring-doc.cadn.net.cn

class Foo

class Bar(private val foo: Foo)

val context = GenericApplicationContext().apply {
	registerBean<Foo>()
	registerBean { Bar(it.getBean()) }
}

当类 Bar 有一个单一构造函数时,你甚至可以只指定 bean 类, 构造函数参数将按类型自动注入:spring-doc.cadn.net.cn

val context = GenericApplicationContext().apply {
	registerBean<Foo>()
	registerBean<Bar>()
}

为了允许更声明式的的方法和更简洁的语法,Spring Framework 提供了 一个 Kotlin bean 定义 DSL 它通过一个简洁的声明式 API 声明一个 ApplicationContextInitializer, 这使你可以处理 profiles 和 Environment 以自定义 bean 的注册方式。spring-doc.cadn.net.cn

在下面的示例中请注意:spring-doc.cadn.net.cn

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 注册到应用上下文中, 如下例所示:spring-doc.cadn.net.cn

val context = GenericApplicationContext().apply {
	myBeans.initialize(this)
	refresh()
}
Spring Boot 基于 JavaConfig 和 尚未提供对函数式 bean 定义的特定支持, 但可以通过 Spring Boot 的 ApplicationContextInitializer 支持进行实验性使用。 请参阅 此 Stack Overflow 回答 以获取更多详细信息和最新信息。另请参见在 Spring Fu 孵化器 中开发的实验性 Kofu DSL。