0
# Dependency Injection
1
2
Micronaut's dependency injection system uses compile-time processing to eliminate reflection and provide fast application startup. It supports the full Jakarta Inject specification plus additional features for modern application development.
3
4
## Capabilities
5
6
### Bean Declaration
7
8
Define beans using standard Jakarta Inject annotations or Micronaut-specific annotations.
9
10
```java { .api }
11
/**
12
* Mark a class as a singleton bean
13
*/
14
@Singleton
15
public class UserService {
16
private final UserRepository repository;
17
18
public UserService(UserRepository repository) {
19
this.repository = repository;
20
}
21
}
22
23
/**
24
* Create beans using factory methods
25
*/
26
@Factory
27
public class DatabaseFactory {
28
29
@Bean
30
@Singleton
31
public DataSource dataSource() {
32
return new HikariDataSource();
33
}
34
}
35
36
/**
37
* Prototype scope (new instance each time)
38
*/
39
@Prototype
40
public class RequestHandler {
41
// New instance for each injection
42
}
43
```
44
45
### Dependency Injection
46
47
Inject dependencies through constructor, field, or method injection.
48
49
```java { .api }
50
/**
51
* Constructor injection (recommended)
52
*/
53
@Singleton
54
public class OrderService {
55
private final PaymentService paymentService;
56
private final InventoryService inventoryService;
57
58
public OrderService(PaymentService paymentService,
59
InventoryService inventoryService) {
60
this.paymentService = paymentService;
61
this.inventoryService = inventoryService;
62
}
63
}
64
65
/**
66
* Field injection
67
*/
68
@Singleton
69
public class NotificationService {
70
@Inject
71
private EmailService emailService;
72
}
73
74
/**
75
* Method injection
76
*/
77
@Singleton
78
public class ConfigService {
79
private DatabaseConfig config;
80
81
@Inject
82
public void setDatabaseConfig(DatabaseConfig config) {
83
this.config = config;
84
}
85
}
86
```
87
88
### Qualifiers
89
90
Use qualifiers to distinguish between multiple implementations of the same interface.
91
92
```java { .api }
93
/**
94
* Named qualifier
95
*/
96
@Singleton
97
@Named("mysql")
98
public class MySqlRepository implements Repository {
99
// MySQL implementation
100
}
101
102
@Singleton
103
@Named("postgres")
104
public class PostgresRepository implements Repository {
105
// PostgreSQL implementation
106
}
107
108
/**
109
* Inject specific implementation
110
*/
111
@Singleton
112
public class DataService {
113
private final Repository repository;
114
115
public DataService(@Named("mysql") Repository repository) {
116
this.repository = repository;
117
}
118
}
119
120
/**
121
* Custom qualifiers
122
*/
123
@Qualifier
124
@Retention(RetentionPolicy.RUNTIME)
125
public @interface Database {
126
String value();
127
}
128
129
@Singleton
130
@Database("primary")
131
public class PrimaryDatabase implements DatabaseService {
132
// Primary database implementation
133
}
134
```
135
136
### Bean Scopes
137
138
Control bean lifecycle with built-in and custom scopes.
139
140
```java { .api }
141
/**
142
* Built-in scopes
143
*/
144
@Singleton // Single instance per application
145
@Prototype // New instance each time
146
@RequestScope // One instance per HTTP request
147
@ThreadLocal // One instance per thread
148
149
/**
150
* Custom scope example
151
*/
152
@Scope
153
@Retention(RetentionPolicy.RUNTIME)
154
public @interface TenantScope {
155
}
156
157
@TenantScope
158
public class TenantService {
159
// One instance per tenant
160
}
161
```
162
163
### Conditional Beans
164
165
Create beans conditionally based on configuration, environment, or other factors.
166
167
```java { .api }
168
/**
169
* Conditional on property value
170
*/
171
@Singleton
172
@Requires(property = "cache.enabled", value = "true")
173
public class CacheService {
174
// Only created if cache.enabled=true
175
}
176
177
/**
178
* Conditional on missing bean
179
*/
180
@Singleton
181
@Requires(missingBeans = CustomMetricsService.class)
182
public class DefaultMetricsService implements MetricsService {
183
// Only created if CustomMetricsService not present
184
}
185
186
/**
187
* Conditional on environment
188
*/
189
@Singleton
190
@Requires(env = Environment.DEVELOPMENT)
191
public class DevelopmentDataLoader {
192
// Only in development environment
193
}
194
195
/**
196
* Custom condition
197
*/
198
@Singleton
199
@Requires(condition = DatabaseAvailableCondition.class)
200
public class DatabaseService {
201
// Custom condition logic
202
}
203
```
204
205
### Bean Factories
206
207
Create complex beans using factory classes and methods.
208
209
```java { .api }
210
/**
211
* Factory class for complex bean creation
212
*/
213
@Factory
214
public class HttpClientFactory {
215
216
@Bean
217
@Singleton
218
@Named("api-client")
219
public HttpClient createApiClient(@Value("${api.base-url}") String baseUrl) {
220
return HttpClient.create(URL.of(baseUrl))
221
.configuration(config -> {
222
config.readTimeout(Duration.ofSeconds(30));
223
config.connectTimeout(Duration.ofSeconds(10));
224
});
225
}
226
227
@Bean
228
@Singleton
229
@Named("auth-client")
230
public HttpClient createAuthClient(@Value("${auth.url}") String authUrl) {
231
return HttpClient.create(URL.of(authUrl));
232
}
233
}
234
235
/**
236
* Parameterized factory for creating multiple similar beans
237
*/
238
@EachProperty("databases")
239
public class DatabaseFactory {
240
private String name;
241
private String url;
242
private String driver;
243
244
@Bean
245
@Singleton
246
public DataSource dataSource() {
247
return DataSourceBuilder.create()
248
.url(url)
249
.driverClassName(driver)
250
.build();
251
}
252
253
// getters and setters
254
}
255
```
256
257
### Bean Validation
258
259
Validate bean properties during creation using Jakarta Bean Validation.
260
261
```java { .api }
262
/**
263
* Bean with validation constraints
264
*/
265
@Singleton
266
public class UserService {
267
268
public User createUser(@Valid @NotNull CreateUserRequest request) {
269
// Method parameter validation
270
return new User(request.getName(), request.getEmail());
271
}
272
}
273
274
/**
275
* Configuration bean with validation
276
*/
277
@ConfigurationProperties("app")
278
public class AppConfiguration {
279
280
@NotBlank
281
private String name;
282
283
@Min(1)
284
@Max(65535)
285
private int port;
286
287
288
private String adminEmail;
289
290
// getters and setters with validation
291
}
292
```
293
294
### Bean Events
295
296
Listen to bean lifecycle events and publish custom events.
297
298
```java { .api }
299
/**
300
* Bean lifecycle events
301
*/
302
@Singleton
303
public class ServiceInitializer {
304
305
@EventListener
306
public void onStartup(StartupEvent event) {
307
// Application startup logic
308
}
309
310
@EventListener
311
public void onShutdown(ShutdownEvent event) {
312
// Cleanup logic
313
}
314
315
@EventListener
316
public void onBeanCreated(BeanCreatedEvent<DataSource> event) {
317
// React to DataSource bean creation
318
DataSource dataSource = event.getBean();
319
// Initialize connection pool, etc.
320
}
321
}
322
323
/**
324
* Custom event publishing
325
*/
326
@Singleton
327
public class OrderService {
328
private final ApplicationEventPublisher eventPublisher;
329
330
public OrderService(ApplicationEventPublisher eventPublisher) {
331
this.eventPublisher = eventPublisher;
332
}
333
334
public void processOrder(Order order) {
335
// Process order
336
eventPublisher.publishEvent(new OrderProcessedEvent(order));
337
}
338
}
339
```
340
341
### Bean Introspection
342
343
Access bean metadata at runtime without reflection.
344
345
```java { .api }
346
/**
347
* Enable introspection for a class
348
*/
349
@Introspected
350
public class Person {
351
private String firstName;
352
private String lastName;
353
private int age;
354
355
// constructors, getters, setters
356
}
357
358
/**
359
* Use introspection to access bean metadata
360
*/
361
@Singleton
362
public class ObjectMapper {
363
364
public Map<String, Object> toMap(Object obj) {
365
BeanIntrospection<Object> introspection =
366
BeanIntrospection.getIntrospection(obj.getClass());
367
368
Map<String, Object> map = new HashMap<>();
369
for (BeanProperty<Object, Object> property : introspection.getBeanProperties()) {
370
Object value = property.get(obj);
371
map.put(property.getName(), value);
372
}
373
return map;
374
}
375
}
376
```
377
378
## Types
379
380
```java { .api }
381
// Core DI interfaces
382
public interface BeanContext extends BeanLocator, LifeCycle<BeanContext> {
383
<T> T getBean(Class<T> beanType);
384
<T> T getBean(Class<T> beanType, Qualifier<T> qualifier);
385
<T> Optional<T> findBean(Class<T> beanType);
386
<T> Collection<T> getBeansOfType(Class<T> beanType);
387
<T> Stream<T> streamOfType(Class<T> beanType);
388
}
389
390
public interface BeanDefinition<T> extends BeanType<T> {
391
Class<T> getBeanType();
392
Optional<Class<?>> getDeclaringType();
393
boolean isEnabled(BeanContext context);
394
boolean isSingleton();
395
boolean isConfigurationProperties();
396
List<Argument<?>> getRequiredArguments();
397
}
398
399
public interface ApplicationContext extends BeanContext, LifeCycle<ApplicationContext> {
400
Environment getEnvironment();
401
ConversionService getConversionService();
402
void publishEvent(Object event);
403
static ApplicationContext build();
404
static ApplicationContext run();
405
}
406
407
// Bean introspection
408
public interface BeanIntrospection<T> {
409
Class<T> getBeanType();
410
Collection<BeanProperty<T, Object>> getBeanProperties();
411
Collection<BeanMethod<T, Object>> getBeanMethods();
412
T instantiate(Object... args);
413
static <T> BeanIntrospection<T> getIntrospection(Class<T> type);
414
}
415
416
public interface BeanProperty<B, T> {
417
Class<T> getType();
418
String getName();
419
T get(B bean);
420
void set(B bean, T value);
421
boolean isReadOnly();
422
boolean isWriteOnly();
423
}
424
425
// Injection points
426
public interface InjectionPoint<T> {
427
BeanDefinition<?> getDeclaringBean();
428
Class<T> getType();
429
Optional<String> getName();
430
AnnotationMetadata getAnnotationMetadata();
431
}
432
433
public interface FieldInjectionPoint<B, T> extends InjectionPoint<T> {
434
Field getField();
435
void set(B instance, T value);
436
}
437
438
public interface MethodInjectionPoint<B, T> extends InjectionPoint<T> {
439
Method getMethod();
440
T invoke(B instance, Object... args);
441
}
442
```