Aware interfaces

A bean that implements an *Aware interface receives its own name, the bean factory, the context or another container object through a method call.

Why

Constructor injection is usually simpler: a bean can inject BeanFactory, ApplicationContext, Environment, ResourceLoader, ApplicationEventPublisher or MessageSource directly. The aware interfaces are for the remaining cases:

Each setter is called once, after injection and before the init callbacks (@PostConstruct, afterPropertiesSet, the init method). The order is:

  1. BeanNameAware.setBeanName;
  2. BeanFactoryAware.setBeanFactory;
  3. EnvironmentAware.setEnvironment;
  4. EmbeddedValueResolverAware.setEmbeddedValueResolver;
  5. ResourceLoaderAware.setResourceLoader;
  6. ApplicationEventPublisherAware.setApplicationEventPublisher;
  7. MessageSourceAware.setMessageSource;
  8. ApplicationContextAware.setApplicationContext.

The first two are called by the bean factory. The others are called by ApplicationContextAwareProcessor, a BeanPostProcessor that every context registers. A bare DefaultListableBeanFactory without a context calls only the first two.

Example

import 'package:spring_core_dart/spring_core_dart.dart';

abstract interface class Plugin {
  void run();
}

// Two workers of one class, registered as 'importer' and 'exporter'.
// Each reads its own settings, keyed by its bean name.
class Worker implements BeanNameAware, EnvironmentAware {
  late final String id;
  late final Environment _environment;

  @override
  void setBeanName(String name) => id = name;

  @override
  void setEnvironment(Environment environment) => _environment = environment;

  int get batchSize =>
      int.parse(_environment.getProperty('workers.$id.batch-size') ?? '100');
}

@Configuration()
class WorkerConfig {
  @Bean()
  Worker importer() => Worker();

  @Bean()
  Worker exporter() => Worker();
}

// Which plugin runs is decided by name at run time.
@Component()
class PluginLoader implements BeanFactoryAware {
  late BeanFactory _factory;

  @override
  void setBeanFactory(BeanFactory beanFactory) => _factory = beanFactory;

  void run(String name) => (_factory.getBeanByName(name) as Plugin).run();
}

// Paths built from properties, resolved at run time.
@Component()
class Paths implements EmbeddedValueResolverAware {
  late String cache;

  @override
  void setEmbeddedValueResolver(StringValueResolver resolver) {
    cache = resolver(r"#{'${app.home:/tmp}' + '/cache'}");
  }
}

Members

Interface Method Receives
BeanNameAware setBeanName(String name) The bean's name, never an alias.
BeanFactoryAware setBeanFactory(BeanFactory beanFactory) The factory that holds the bean.
EnvironmentAware setEnvironment(Environment environment) The context's environment.
EmbeddedValueResolverAware setEmbeddedValueResolver(StringValueResolver resolver) A function that resolves ${...} placeholders, then #{...} expressions, like @Value.
ResourceLoaderAware setResourceLoader(ResourceLoader resourceLoader) The context, as resource loader. Custom protocols added to it work.
ApplicationEventPublisherAware setApplicationEventPublisher(ApplicationEventPublisher publisher) The context, as event publisher.
MessageSourceAware setMessageSource(MessageSource messageSource) The context, which looks messages up in the messageSource bean.
ApplicationContextAware setApplicationContext(ApplicationContext applicationContext) The context that created the bean.

Aware is the common supertype. It has no methods.

In Spring (Java)

class Worker implements BeanNameAware, EnvironmentAware {
  String id;
  Environment environment;

  @Override public void setBeanName(String name) { id = name; }
  @Override public void setEnvironment(Environment env) { environment = env; }
}

Differences that matter:

See also