|
1 | 1 | [[kotlin-bean-definition-dsl]]
|
2 | 2 | = Bean Definition DSL
|
3 | 3 |
|
4 |
| -Spring Framework supports registering beans in a functional way by using lambdas |
5 |
| -as an alternative to XML or Java configuration (`@Configuration` and `@Bean`). In a nutshell, |
6 |
| -it lets you register beans with a lambda that acts as a `FactoryBean`. |
7 |
| -This mechanism is very efficient, as it does not require any reflection or CGLIB proxies. |
8 |
| - |
9 |
| -In Java, you can, for example, write the following: |
10 |
| - |
11 |
| -[source,java,indent=0] |
12 |
| ----- |
13 |
| - class Foo {} |
14 |
| -
|
15 |
| - class Bar { |
16 |
| - private final Foo foo; |
17 |
| - public Bar(Foo foo) { |
18 |
| - this.foo = foo; |
19 |
| - } |
20 |
| - } |
21 |
| -
|
22 |
| - GenericApplicationContext context = new GenericApplicationContext(); |
23 |
| - context.registerBean(Foo.class); |
24 |
| - context.registerBean(Bar.class, () -> new Bar(context.getBean(Foo.class))); |
25 |
| ----- |
26 |
| - |
27 |
| -In Kotlin, with reified type parameters and `GenericApplicationContext` Kotlin extensions, |
28 |
| -you can instead write the following: |
29 |
| - |
30 |
| -[source,kotlin,indent=0] |
31 |
| ----- |
32 |
| - class Foo |
33 |
| -
|
34 |
| - class Bar(private val foo: Foo) |
35 |
| -
|
36 |
| - val context = GenericApplicationContext().apply { |
37 |
| - registerBean<Foo>() |
38 |
| - registerBean { Bar(it.getBean()) } |
39 |
| - } |
40 |
| ----- |
41 |
| - |
42 |
| -When the class `Bar` has a single constructor, you can even just specify the bean class, |
43 |
| -the constructor parameters will be autowired by type: |
44 |
| - |
45 |
| -[source,kotlin,indent=0] |
46 |
| ----- |
47 |
| - val context = GenericApplicationContext().apply { |
48 |
| - registerBean<Foo>() |
49 |
| - registerBean<Bar>() |
50 |
| - } |
51 |
| ----- |
52 |
| - |
53 |
| -In order to allow a more declarative approach and cleaner syntax, Spring Framework provides |
54 |
| -a {spring-framework-api-kdoc}/spring-context/org.springframework.context.support/-bean-definition-dsl/index.html[Kotlin bean definition DSL] |
55 |
| -It declares an `ApplicationContextInitializer` through a clean declarative API, |
56 |
| -which lets you deal with profiles and `Environment` for customizing |
57 |
| -how beans are registered. |
58 |
| - |
59 |
| -In the following example notice that: |
60 |
| - |
61 |
| -* Type inference usually allows to avoid specifying the type for bean references like `ref("bazBean")` |
62 |
| -* It is possible to use Kotlin top level functions to declare beans using callable references like `bean(::myRouter)` in this example |
63 |
| -* When specifying `bean<Bar>()` or `bean(::myRouter)`, parameters are autowired by type |
64 |
| -* The `FooBar` bean will be registered only if the `foobar` profile is active |
65 |
| - |
66 |
| -[source,kotlin,indent=0] |
67 |
| ----- |
68 |
| - class Foo |
69 |
| - class Bar(private val foo: Foo) |
70 |
| - class Baz(var message: String = "") |
71 |
| - class FooBar(private val baz: Baz) |
72 |
| -
|
73 |
| - val myBeans = beans { |
74 |
| - bean<Foo>() |
75 |
| - bean<Bar>() |
76 |
| - bean("bazBean") { |
77 |
| - Baz().apply { |
78 |
| - message = "Hello world" |
79 |
| - } |
80 |
| - } |
81 |
| - profile("foobar") { |
82 |
| - bean { FooBar(ref("bazBean")) } |
83 |
| - } |
84 |
| - bean(::myRouter) |
85 |
| - } |
86 |
| -
|
87 |
| - fun myRouter(foo: Foo, bar: Bar, baz: Baz) = router { |
88 |
| - // ... |
89 |
| - } |
90 |
| ----- |
91 |
| - |
92 |
| -NOTE: This DSL is programmatic, meaning it allows custom registration logic of beans |
93 |
| -through an `if` expression, a `for` loop, or any other Kotlin constructs. |
94 |
| - |
95 |
| -You can then use this `beans()` function to register beans on the application context, |
96 |
| -as the following example shows: |
97 |
| - |
98 |
| -[source,kotlin,indent=0] |
99 |
| ----- |
100 |
| - val context = GenericApplicationContext().apply { |
101 |
| - myBeans.initialize(this) |
102 |
| - refresh() |
103 |
| - } |
104 |
| ----- |
105 |
| - |
106 |
| -NOTE: Spring Boot is based on JavaConfig and |
107 |
| -{spring-boot-issues}/8115[does not yet provide specific support for functional bean definition], |
108 |
| -but you can experimentally use functional bean definitions through Spring Boot's `ApplicationContextInitializer` support. |
109 |
| -See {stackoverflow-questions}/45935931/how-to-use-functional-bean-definition-kotlin-dsl-with-spring-boot-and-spring-w/46033685#46033685[this Stack Overflow answer] |
110 |
| -for more details and up-to-date information. See also the experimental Kofu DSL developed in {spring-github-org}-experimental/spring-fu[Spring Fu incubator]. |
| 4 | +See xref:core/beans/java/programmatic-bean-registration.adoc[Programmatic Bean Registration]. |
111 | 5 |
|
112 | 6 |
|
113 | 7 |
|
|
0 commit comments