0
# Bean Factory and Advanced Configuration
1
2
The bean factory pattern provides programmatic bean creation, advanced configuration building, and runtime bean registration capabilities. This enables dynamic bean creation and complex configuration scenarios.
3
4
## Factory Pattern
5
6
### @Factory Annotation
7
8
Marks a class as a bean factory for creating and configuring other beans.
9
10
```java { .api }
11
@Target({TYPE})
12
@Retention(RUNTIME)
13
@Documented
14
public @interface Factory {
15
}
16
```
17
18
### @Bean Annotation
19
20
Marks methods within factory classes that produce bean instances.
21
22
```java { .api }
23
@Target({METHOD})
24
@Retention(RUNTIME)
25
@Documented
26
public @interface Bean {
27
/**
28
* Bean name override
29
*/
30
String named() default "";
31
32
/**
33
* Pre-destroy method name
34
*/
35
String preDestroy() default "";
36
}
37
```
38
39
**Usage Examples:**
40
41
```java
42
import io.micronaut.context.annotation.Factory;
43
import io.micronaut.context.annotation.Bean;
44
import jakarta.inject.Singleton;
45
46
@Factory
47
public class DatabaseConfigurationFactory {
48
49
@Bean
50
@Singleton
51
public DataSource primaryDataSource() {
52
HikariConfig config = new HikariConfig();
53
config.setJdbcUrl("jdbc:h2:mem:testdb");
54
config.setUsername("sa");
55
config.setPassword("");
56
config.setMaximumPoolSize(10);
57
return new HikariDataSource(config);
58
}
59
60
@Bean
61
@Singleton
62
@Named("readonly")
63
public DataSource readOnlyDataSource() {
64
HikariConfig config = new HikariConfig();
65
config.setJdbcUrl("jdbc:h2:mem:readonly");
66
config.setUsername("reader");
67
config.setReadOnly(true);
68
return new HikariDataSource(config);
69
}
70
71
@Bean
72
@Singleton
73
public EntityManagerFactory entityManagerFactory(DataSource dataSource) {
74
LocalContainerEntityManagerFactoryBean factory =
75
new LocalContainerEntityManagerFactoryBean();
76
factory.setDataSource(dataSource);
77
factory.setPackagesToScan("com.example.entities");
78
factory.afterPropertiesSet();
79
return factory.getObject();
80
}
81
}
82
```
83
84
### Complex Factory Configuration
85
86
```java
87
@Factory
88
public class HttpClientFactory {
89
90
@Value("${http.timeout:30s}")
91
private Duration timeout;
92
93
@Value("${http.max-connections:100}")
94
private int maxConnections;
95
96
@Bean
97
@Singleton
98
public HttpClient defaultHttpClient() {
99
return HttpClient.newBuilder()
100
.connectTimeout(timeout)
101
.build();
102
}
103
104
@Bean
105
@Singleton
106
@Named("secure")
107
public HttpClient secureHttpClient() {
108
SSLContext sslContext = createCustomSSLContext();
109
return HttpClient.newBuilder()
110
.connectTimeout(timeout)
111
.sslContext(sslContext)
112
.build();
113
}
114
115
@Bean
116
@Singleton
117
public ConnectionPool connectionPool() {
118
return new ConnectionPool.Builder()
119
.maxConnections(maxConnections)
120
.keepAliveDuration(5, TimeUnit.MINUTES)
121
.build();
122
}
123
124
private SSLContext createCustomSSLContext() {
125
// Custom SSL context creation logic
126
return SSLContext.getDefault();
127
}
128
}
129
```
130
131
## Runtime Bean Registration
132
133
### RuntimeBeanDefinition
134
135
Interface for creating bean definitions programmatically at runtime.
136
137
```java { .api }
138
/**
139
* Interface for runtime bean definition creation
140
* @param <T> The bean type
141
*/
142
public interface RuntimeBeanDefinition<T> extends BeanDefinition<T> {
143
/**
144
* Create a runtime bean definition for the given type
145
* @param type The bean type
146
* @return RuntimeBeanDefinition instance
147
*/
148
static <T> RuntimeBeanDefinition<T> of(Class<T> type);
149
150
/**
151
* Create a runtime bean definition with custom factory
152
* @param type The bean type
153
* @param factory The bean factory
154
* @return RuntimeBeanDefinition instance
155
*/
156
static <T> RuntimeBeanDefinition<T> of(Class<T> type, BeanFactory<T> factory);
157
158
/**
159
* Create a runtime bean definition for a singleton instance
160
* @param instance The singleton instance
161
* @return RuntimeBeanDefinition instance
162
*/
163
static <T> RuntimeBeanDefinition<T> of(T instance);
164
165
/**
166
* Add a qualifier to this bean definition
167
* @param qualifier The qualifier
168
* @return This bean definition
169
*/
170
RuntimeBeanDefinition<T> qualifier(Class<? extends Annotation> qualifier);
171
172
/**
173
* Mark this bean as singleton
174
* @return This bean definition
175
*/
176
RuntimeBeanDefinition<T> singleton();
177
178
/**
179
* Mark this bean as prototype
180
* @return This bean definition
181
*/
182
RuntimeBeanDefinition<T> prototype();
183
}
184
```
185
186
**Usage Examples:**
187
188
```java
189
import io.micronaut.context.RuntimeBeanDefinition;
190
import io.micronaut.context.ApplicationContext;
191
192
public class DynamicBeanRegistration {
193
194
public void registerDynamicBeans(ApplicationContext context) {
195
// Register a simple singleton bean
196
RuntimeBeanDefinition<MyService> serviceDef =
197
RuntimeBeanDefinition.of(MyService.class).singleton();
198
context.registerBeanDefinition(serviceDef);
199
200
// Register bean with custom factory
201
RuntimeBeanDefinition<ComplexService> complexDef =
202
RuntimeBeanDefinition.of(ComplexService.class, (resolutionContext, beanContext) -> {
203
ComplexService service = new ComplexService();
204
service.configure(beanContext.getBean(Configuration.class));
205
return service;
206
}).singleton();
207
context.registerBeanDefinition(complexDef);
208
209
// Register singleton instance
210
MyConfiguration config = new MyConfiguration();
211
config.setProperty("value", "runtime-configured");
212
RuntimeBeanDefinition<MyConfiguration> configDef =
213
RuntimeBeanDefinition.of(config);
214
context.registerBeanDefinition(configDef);
215
216
// Register with qualifier
217
RuntimeBeanDefinition<DatabaseService> dbDef =
218
RuntimeBeanDefinition.of(DatabaseService.class)
219
.qualifier(Named.class)
220
.singleton();
221
context.registerBeanDefinition(dbDef);
222
}
223
}
224
```
225
226
## Advanced Configuration Patterns
227
228
### @ConfigurationBuilder
229
230
Enables configuration of complex objects through builder pattern integration.
231
232
```java { .api }
233
@Target({FIELD, METHOD, PARAMETER})
234
@Retention(RUNTIME)
235
@Documented
236
public @interface ConfigurationBuilder {
237
/**
238
* Property prefix for configuration values
239
*/
240
String value() default "";
241
242
/**
243
* Configuration prefix for nested configuration
244
*/
245
String configurationPrefix() default "";
246
247
/**
248
* Method prefixes to include
249
*/
250
String[] includes() default {};
251
252
/**
253
* Method prefixes to exclude
254
*/
255
String[] excludes() default {};
256
257
/**
258
* Whether to allow zero args methods
259
*/
260
boolean allowZeroArgs() default false;
261
}
262
```
263
264
**Usage Examples:**
265
266
```java
267
import io.micronaut.context.annotation.ConfigurationProperties;
268
import io.micronaut.context.annotation.ConfigurationBuilder;
269
270
@ConfigurationProperties("datasource")
271
public class DataSourceConfig {
272
273
@ConfigurationBuilder(configurationPrefix = "hikari")
274
private final HikariConfig hikariConfig = new HikariConfig();
275
276
@ConfigurationBuilder(configurationPrefix = "connection-pool")
277
private final ConnectionPoolSettings poolSettings = new ConnectionPoolSettings();
278
279
public HikariConfig getHikariConfig() {
280
return hikariConfig;
281
}
282
283
public ConnectionPoolSettings getPoolSettings() {
284
return poolSettings;
285
}
286
}
287
288
// Enables configuration like:
289
// datasource.hikari.maximum-pool-size=20
290
// datasource.hikari.minimum-idle=5
291
// datasource.connection-pool.max-lifetime=1800000
292
```
293
294
### @EachBean and @EachProperty
295
296
Dynamic bean creation based on configuration entries.
297
298
```java { .api }
299
@Target({TYPE})
300
@Retention(RUNTIME)
301
@Documented
302
public @interface EachBean {
303
/**
304
* The bean type to iterate over
305
*/
306
Class<?> value();
307
}
308
309
@Target({TYPE})
310
@Retention(RUNTIME)
311
@Documented
312
public @interface EachProperty {
313
/**
314
* The property prefix to iterate over
315
*/
316
String value();
317
318
/**
319
* Primary bean marker
320
*/
321
boolean primary() default false;
322
}
323
```
324
325
**Usage Examples:**
326
327
```java
328
// Configuration-driven bean creation
329
@EachProperty("databases")
330
@ConfigurationProperties("databases")
331
public class DatabaseConfig {
332
private String url;
333
private String username;
334
private String password;
335
336
// getters and setters
337
}
338
339
@EachBean(DatabaseConfig.class)
340
@Singleton
341
public class DatabaseService {
342
343
private final DatabaseConfig config;
344
345
public DatabaseService(DatabaseConfig config) {
346
this.config = config;
347
}
348
349
public Connection getConnection() {
350
return DriverManager.getConnection(
351
config.getUrl(),
352
config.getUsername(),
353
config.getPassword()
354
);
355
}
356
}
357
358
// Configuration example:
359
// databases.primary.url=jdbc:postgresql://localhost/primary
360
// databases.primary.username=user1
361
// databases.secondary.url=jdbc:postgresql://localhost/secondary
362
// databases.secondary.username=user2
363
```
364
365
## Bean Lifecycle and Management
366
367
### BeanFactory Interface
368
369
Core interface for custom bean creation logic.
370
371
```java { .api }
372
/**
373
* Factory interface for creating bean instances
374
* @param <T> The bean type
375
*/
376
public interface BeanFactory<T> {
377
/**
378
* Build a bean instance
379
* @param resolutionContext The resolution context
380
* @param context The bean context
381
* @param definition The bean definition
382
* @return Bean instance
383
*/
384
T build(BeanResolutionContext resolutionContext, BeanContext context, BeanDefinition<T> definition);
385
386
/**
387
* Build a bean instance with additional arguments
388
* @param resolutionContext The resolution context
389
* @param context The bean context
390
* @param definition The bean definition
391
* @param args Additional constructor arguments
392
* @return Bean instance
393
*/
394
default T build(BeanResolutionContext resolutionContext, BeanContext context,
395
BeanDefinition<T> definition, Object... args) {
396
return build(resolutionContext, context, definition);
397
}
398
}
399
```
400
401
### Bean Registration and Management
402
403
```java { .api }
404
public interface BeanDefinitionRegistry {
405
/**
406
* Register a bean definition
407
* @param beanDefinition The bean definition to register
408
* @return The bean definition
409
*/
410
<T> BeanDefinition<T> registerBeanDefinition(BeanDefinition<T> beanDefinition);
411
412
/**
413
* Register a singleton bean instance
414
* @param type The bean type
415
* @param singleton The singleton instance
416
* @return The application context
417
*/
418
<T> ApplicationContext registerSingleton(Class<T> type, T singleton);
419
420
/**
421
* Register a singleton bean with qualifier
422
* @param type The bean type
423
* @param singleton The singleton instance
424
* @param qualifier The qualifier
425
* @return The application context
426
*/
427
<T> ApplicationContext registerSingleton(Class<T> type, T singleton, Qualifier<T> qualifier);
428
}
429
```
430
431
## Types
432
433
### Factory-related Types
434
435
```java { .api }
436
public interface BeanCreationContext<T> extends BeanResolutionContext {
437
BeanDefinition<T> definition();
438
CreatedBean<T> create() throws BeanCreationException;
439
}
440
441
public interface CreatedBean<T> {
442
BeanDefinition<T> definition();
443
T bean();
444
445
default void inject(BeanResolutionContext resolutionContext, BeanContext context) {
446
// Perform injection on the created bean
447
}
448
}
449
450
public class BeanCreationException extends BeanContextException {
451
public BeanCreationException(String message);
452
public BeanCreationException(String message, Throwable cause);
453
public BeanCreationException(BeanDefinition<?> definition, String message);
454
public BeanCreationException(BeanDefinition<?> definition, String message, Throwable cause);
455
456
public Optional<BeanDefinition<?>> getBeanDefinition();
457
}
458
```