Core dependency injection interfaces and components for the Micronaut Framework
—
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.
Marks a class as a bean factory for creating and configuring other beans.
@Target({TYPE})
@Retention(RUNTIME)
@Documented
public @interface Factory {
}Marks methods within factory classes that produce bean instances.
@Target({METHOD})
@Retention(RUNTIME)
@Documented
public @interface Bean {
/**
* Bean name override
*/
String named() default "";
/**
* Pre-destroy method name
*/
String preDestroy() default "";
}Usage Examples:
import io.micronaut.context.annotation.Factory;
import io.micronaut.context.annotation.Bean;
import jakarta.inject.Singleton;
@Factory
public class DatabaseConfigurationFactory {
@Bean
@Singleton
public DataSource primaryDataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:h2:mem:testdb");
config.setUsername("sa");
config.setPassword("");
config.setMaximumPoolSize(10);
return new HikariDataSource(config);
}
@Bean
@Singleton
@Named("readonly")
public DataSource readOnlyDataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:h2:mem:readonly");
config.setUsername("reader");
config.setReadOnly(true);
return new HikariDataSource(config);
}
@Bean
@Singleton
public EntityManagerFactory entityManagerFactory(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean factory =
new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(dataSource);
factory.setPackagesToScan("com.example.entities");
factory.afterPropertiesSet();
return factory.getObject();
}
}@Factory
public class HttpClientFactory {
@Value("${http.timeout:30s}")
private Duration timeout;
@Value("${http.max-connections:100}")
private int maxConnections;
@Bean
@Singleton
public HttpClient defaultHttpClient() {
return HttpClient.newBuilder()
.connectTimeout(timeout)
.build();
}
@Bean
@Singleton
@Named("secure")
public HttpClient secureHttpClient() {
SSLContext sslContext = createCustomSSLContext();
return HttpClient.newBuilder()
.connectTimeout(timeout)
.sslContext(sslContext)
.build();
}
@Bean
@Singleton
public ConnectionPool connectionPool() {
return new ConnectionPool.Builder()
.maxConnections(maxConnections)
.keepAliveDuration(5, TimeUnit.MINUTES)
.build();
}
private SSLContext createCustomSSLContext() {
// Custom SSL context creation logic
return SSLContext.getDefault();
}
}Interface for creating bean definitions programmatically at runtime.
/**
* Interface for runtime bean definition creation
* @param <T> The bean type
*/
public interface RuntimeBeanDefinition<T> extends BeanDefinition<T> {
/**
* Create a runtime bean definition for the given type
* @param type The bean type
* @return RuntimeBeanDefinition instance
*/
static <T> RuntimeBeanDefinition<T> of(Class<T> type);
/**
* Create a runtime bean definition with custom factory
* @param type The bean type
* @param factory The bean factory
* @return RuntimeBeanDefinition instance
*/
static <T> RuntimeBeanDefinition<T> of(Class<T> type, BeanFactory<T> factory);
/**
* Create a runtime bean definition for a singleton instance
* @param instance The singleton instance
* @return RuntimeBeanDefinition instance
*/
static <T> RuntimeBeanDefinition<T> of(T instance);
/**
* Add a qualifier to this bean definition
* @param qualifier The qualifier
* @return This bean definition
*/
RuntimeBeanDefinition<T> qualifier(Class<? extends Annotation> qualifier);
/**
* Mark this bean as singleton
* @return This bean definition
*/
RuntimeBeanDefinition<T> singleton();
/**
* Mark this bean as prototype
* @return This bean definition
*/
RuntimeBeanDefinition<T> prototype();
}Usage Examples:
import io.micronaut.context.RuntimeBeanDefinition;
import io.micronaut.context.ApplicationContext;
public class DynamicBeanRegistration {
public void registerDynamicBeans(ApplicationContext context) {
// Register a simple singleton bean
RuntimeBeanDefinition<MyService> serviceDef =
RuntimeBeanDefinition.of(MyService.class).singleton();
context.registerBeanDefinition(serviceDef);
// Register bean with custom factory
RuntimeBeanDefinition<ComplexService> complexDef =
RuntimeBeanDefinition.of(ComplexService.class, (resolutionContext, beanContext) -> {
ComplexService service = new ComplexService();
service.configure(beanContext.getBean(Configuration.class));
return service;
}).singleton();
context.registerBeanDefinition(complexDef);
// Register singleton instance
MyConfiguration config = new MyConfiguration();
config.setProperty("value", "runtime-configured");
RuntimeBeanDefinition<MyConfiguration> configDef =
RuntimeBeanDefinition.of(config);
context.registerBeanDefinition(configDef);
// Register with qualifier
RuntimeBeanDefinition<DatabaseService> dbDef =
RuntimeBeanDefinition.of(DatabaseService.class)
.qualifier(Named.class)
.singleton();
context.registerBeanDefinition(dbDef);
}
}Enables configuration of complex objects through builder pattern integration.
@Target({FIELD, METHOD, PARAMETER})
@Retention(RUNTIME)
@Documented
public @interface ConfigurationBuilder {
/**
* Property prefix for configuration values
*/
String value() default "";
/**
* Configuration prefix for nested configuration
*/
String configurationPrefix() default "";
/**
* Method prefixes to include
*/
String[] includes() default {};
/**
* Method prefixes to exclude
*/
String[] excludes() default {};
/**
* Whether to allow zero args methods
*/
boolean allowZeroArgs() default false;
}Usage Examples:
import io.micronaut.context.annotation.ConfigurationProperties;
import io.micronaut.context.annotation.ConfigurationBuilder;
@ConfigurationProperties("datasource")
public class DataSourceConfig {
@ConfigurationBuilder(configurationPrefix = "hikari")
private final HikariConfig hikariConfig = new HikariConfig();
@ConfigurationBuilder(configurationPrefix = "connection-pool")
private final ConnectionPoolSettings poolSettings = new ConnectionPoolSettings();
public HikariConfig getHikariConfig() {
return hikariConfig;
}
public ConnectionPoolSettings getPoolSettings() {
return poolSettings;
}
}
// Enables configuration like:
// datasource.hikari.maximum-pool-size=20
// datasource.hikari.minimum-idle=5
// datasource.connection-pool.max-lifetime=1800000Dynamic bean creation based on configuration entries.
@Target({TYPE})
@Retention(RUNTIME)
@Documented
public @interface EachBean {
/**
* The bean type to iterate over
*/
Class<?> value();
}
@Target({TYPE})
@Retention(RUNTIME)
@Documented
public @interface EachProperty {
/**
* The property prefix to iterate over
*/
String value();
/**
* Primary bean marker
*/
boolean primary() default false;
}Usage Examples:
// Configuration-driven bean creation
@EachProperty("databases")
@ConfigurationProperties("databases")
public class DatabaseConfig {
private String url;
private String username;
private String password;
// getters and setters
}
@EachBean(DatabaseConfig.class)
@Singleton
public class DatabaseService {
private final DatabaseConfig config;
public DatabaseService(DatabaseConfig config) {
this.config = config;
}
public Connection getConnection() {
return DriverManager.getConnection(
config.getUrl(),
config.getUsername(),
config.getPassword()
);
}
}
// Configuration example:
// databases.primary.url=jdbc:postgresql://localhost/primary
// databases.primary.username=user1
// databases.secondary.url=jdbc:postgresql://localhost/secondary
// databases.secondary.username=user2Core interface for custom bean creation logic.
/**
* Factory interface for creating bean instances
* @param <T> The bean type
*/
public interface BeanFactory<T> {
/**
* Build a bean instance
* @param resolutionContext The resolution context
* @param context The bean context
* @param definition The bean definition
* @return Bean instance
*/
T build(BeanResolutionContext resolutionContext, BeanContext context, BeanDefinition<T> definition);
/**
* Build a bean instance with additional arguments
* @param resolutionContext The resolution context
* @param context The bean context
* @param definition The bean definition
* @param args Additional constructor arguments
* @return Bean instance
*/
default T build(BeanResolutionContext resolutionContext, BeanContext context,
BeanDefinition<T> definition, Object... args) {
return build(resolutionContext, context, definition);
}
}public interface BeanDefinitionRegistry {
/**
* Register a bean definition
* @param beanDefinition The bean definition to register
* @return The bean definition
*/
<T> BeanDefinition<T> registerBeanDefinition(BeanDefinition<T> beanDefinition);
/**
* Register a singleton bean instance
* @param type The bean type
* @param singleton The singleton instance
* @return The application context
*/
<T> ApplicationContext registerSingleton(Class<T> type, T singleton);
/**
* Register a singleton bean with qualifier
* @param type The bean type
* @param singleton The singleton instance
* @param qualifier The qualifier
* @return The application context
*/
<T> ApplicationContext registerSingleton(Class<T> type, T singleton, Qualifier<T> qualifier);
}public interface BeanCreationContext<T> extends BeanResolutionContext {
BeanDefinition<T> definition();
CreatedBean<T> create() throws BeanCreationException;
}
public interface CreatedBean<T> {
BeanDefinition<T> definition();
T bean();
default void inject(BeanResolutionContext resolutionContext, BeanContext context) {
// Perform injection on the created bean
}
}
public class BeanCreationException extends BeanContextException {
public BeanCreationException(String message);
public BeanCreationException(String message, Throwable cause);
public BeanCreationException(BeanDefinition<?> definition, String message);
public BeanCreationException(BeanDefinition<?> definition, String message, Throwable cause);
public Optional<BeanDefinition<?>> getBeanDefinition();
}Install with Tessl CLI
npx tessl i tessl/maven-io-micronaut--micronaut-inject