Bean Definition DSL

Spring Framework 支持使用 Lambda 表达式(作为 XML 或 Java 配置(@Configuration@Bean)的替代方式)以函数方式注册 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 框架提供了https://docs.spring.io/spring-framework/docs/current/kdoc-api/spring-context/org.springframework.context.support/-bean-definition-dsl/index.html[Kotlin Bean 定义 DSL] 它通过一个简洁的声明性 API 声明 ApplicationContextInitializer,使您可以处理配置文件和 `Environment`以自定义注册 Bean 的方式。

在以下示例中,请注意:

  • 类型推断通常允许避免为 Bean 引用指定类型,例如 ref("bazBean")

  • 可以使用 Kotlin 顶级函数来使用此示例中的可调用引用来声明 Bean,如 bean(::myRouter)

  • 指定 bean&lt;Bar&gt;()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。