
# ApplicationContext

`ApplicationContext` is the running container: it holds the beans and gives access to the configuration, events, translated messages and resource files.

## Why

Most code never touches the context. Beans receive what they need by injection: other beans, an `ApplicationEventPublisher`, a `MessageSource`, the `Environment`. You meet the context in these places:

- in `main`, where `ApplicationContext.run` (or Spring Boot's `SpringApplication.run`) creates and starts it;
- in tests;
- in code outside the container that needs a bean, such as a Flutter widget;
- in a bean that must look beans up at run time or shut the application down. It can inject `ApplicationContext` or `ConfigurableApplicationContext`.

There are three types:

- `ApplicationContext` reads: beans, events, messages, resources, the environment.
- `ConfigurableApplicationContext` adds what the owner of the context needs: `register`, `refresh`, `close`, `pause`, `restart`.
- `AnnotationConfigApplicationContext` is the only implementation. It builds its beans from [BeanModule](bean-module.md)s.

### Starting

`ApplicationContext.run(modules)` creates an `AnnotationConfigApplicationContext` and calls `refresh()`. `ApplicationContext.runAsync(modules)` calls `refreshAsync()` instead. Use it when an init callback returns a `Future`, or when a `@PropertySource` reads a file that is only available asynchronously, such as a Flutter asset.

`refresh()` does, in order:

1. check the required properties;
2. load the modules: their `@PropertySource` files and conditions decide which beans exist;
3. run the [BeanFactoryPostProcessor](bean-factory-post-processor.md)s;
4. register the [BeanPostProcessor](bean-post-processor.md)s;
5. set up the message source and the event multicaster, and register the listeners;
6. check the bean graph: a missing or ambiguous dependency, or a cycle, fails here, before any constructor runs;
7. create every singleton that is not lazy;
8. start the auto-startup [SmartLifecycle](lifecycle.md) beans;
9. publish `ContextRefreshedEvent`.

When a step fails, the lifecycle beans already started are stopped, the created singletons are destroyed and the error is rethrown. The context is then unusable. `refresh()` may be called once; a second call throws a `StateError`.

Construct `AnnotationConfigApplicationContext` yourself when something must happen between creating the context and starting it: `register` more modules or registrars, `registerBean` a bean in code, `addBeanFactoryPostProcessor`, set a `parent`.

### Closing

`close()` publishes `ContextClosedEvent`, stops the running lifecycle beans and destroys the singletons, each after the beans that depend on it. It does not wait for asynchronous work. `closeAsync()` waits for `SmartLifecycle` stop callbacks and for destroy callbacks that return a `Future`. A second call does nothing.

`registerShutdownHook()` runs `closeAsync()` on SIGINT or SIGTERM, then ends the process with `128 + signal`. It does nothing on the web.

### Pausing

`pause()` stops the running lifecycle beans but keeps every bean, then publishes `ContextPausedEvent`. `restart()` starts the auto-startup beans again and publishes `ContextRestartedEvent`. A Flutter app calls them when it goes to the background and comes back. `start()` and `stop()` start and stop every lifecycle bean, auto-startup or not.

### Replacing parts of the context

Declare a bean with one of these names to replace a part of the context:

| Bean name | Type | Default |
|---|---|---|
| `messageSource` | `MessageSource` | an empty `DelegatingMessageSource` that asks the parent |
| `applicationEventMulticaster` | `ApplicationEventMulticaster` | a synchronous `SimpleApplicationEventMulticaster` |
| `lifecycleProcessor` | `LifecycleProcessor` | a `DefaultLifecycleProcessor` |
| `conversionService` | `ConversionService` | the environment's conversion service |

## Example

```dart
import 'package:spring_core_dart/spring_core_dart.dart';
import 'package:my_app/src/beans.dart';

const log = SpringLog('my_app');

class UserLoggedIn {
  UserLoggedIn(this.name);
  final String name;
}

void main() {
  // The `dev` profile is set before any bean definition is loaded.
  final context = ApplicationContext.run(
    [appBeans],
    environment: StandardEnvironment()..setActiveProfiles(['dev']),
  )..registerShutdownHook();

  // Beans.
  final auth = context.getBean<AuthFacade>();
  final audit = context.findBean<Audit>(); // null when absent
  final smtp = context.getBean<Transport>(qualifier: 'smtp');

  // Events, from code that is not a bean.
  final registration = context.addListener<UserLoggedIn>(
    (event) => log.info('logged in: ${event.name}'),
  );
  context.publishEvent(UserLoggedIn('ada'));
  registration.remove();

  // Messages, resources, configuration.
  final title = context.getMessage('app.title', locale: 'de');
  final template = context.getResource('resources:templates/mail.txt');
  final port = context.environment.getProperty('server.port');
}
```

A context set up before it starts:

```dart
Future<void> main() async {
  final context = AnnotationConfigApplicationContext([appBeans])
    ..register(pluginBeans)
    ..register(const MessagingRegistrar())
    ..registerBean<Clock>((_) => SystemClock(), name: 'clock')
    ..addBeanFactoryPostProcessor(MakeReportsLazy());
  await context.refreshAsync();
  try {
    context.getBean<App>().run();
  } finally {
    await context.closeAsync();
  }
}
```

## Members

`ApplicationContext` (it is also a `ListableBeanFactory`, `HierarchicalBeanFactory`, `MessageSource`, `ApplicationEventPublisher` and `ResourcePatternResolver`):

| Member | Meaning |
|---|---|
| `static run(modules, {parent, environment, resourceLoader, id})` | Creates a context for the modules and calls `refresh()`. |
| `static runAsync(modules, {...})` | The same with `refreshAsync()`. |
| `getBean<T>({qualifier})` | The bean of `T`. Throws when none or several match. |
| `findBean<T>({qualifier})` | The bean of `T`, or `null` when none matches. |
| `getBeanByName(name)` | The bean with that name or alias. `&name` gives a [FactoryBean](factory-bean.md) itself. |
| `getBeanProvider<T>({qualifier})` | An [ObjectProvider](object-provider.md) that looks the beans up when used. |
| `getBeansOfType<T>()`, `getSortedBeans<T>()` | Every bean of `T`, by name or in order. |
| `containsBean(name)`, `getBeanNamesForType(type)`, `getType(name)` | Questions about the beans, without creating them. |
| `publishEvent(event)` | Sends an event to the listeners. Any object can be an event. |
| `addListener<E>(listener, {order})` | Calls a function for every event of `E`. Returns a `ListenerRegistration`. |
| `getMessage(code, {args, defaultMessage, locale})` | A translated message. |
| `getResource(location)`, `getResources(pattern)` | Files by location (`resources:`, `file:`, patterns). |
| `environment` | Properties, profiles and conversion. |
| `autowireCapableBeanFactory` | Injects objects the container did not create (`@Configurable`). |
| `parent` | The parent context, or `null`. |
| `id`, `displayName`, `startupDate` | For logs and diagnostics. |

`ConfigurableApplicationContext` adds:

| Member | Meaning |
|---|---|
| `register(component)` | Before `refresh`: adds a `BeanModule`, a `BeanRegistrar`, an `ImportSelector` or an `ImportBeanDefinitionRegistrar`. |
| `addBeanFactoryPostProcessor(processor)` | A post-processor that runs before the post-processor beans. |
| `addApplicationListener(listener)`, `removeApplicationListener(listener)` | Listener objects that are not beans. |
| `addProtocolResolver(resolver)` | A custom location prefix for `getResource`, such as `asset:`. |
| `beanFactory` | The [ConfigurableListableBeanFactory](configurable-listable-bean-factory.md) inside the context. |
| `refresh()`, `refreshAsync()` | Starts the context. Call one of them once. |
| `close()`, `closeAsync()` | Stops the lifecycle beans and destroys the singletons. |
| `registerShutdownHook()` | Closes the context on SIGINT or SIGTERM. |
| `start()`, `stop()` | Starts or stops every lifecycle bean. |
| `pause()`, `pauseAsync()`, `restart()` | Pauses and resumes the pauseable lifecycle beans. |
| `isActive`, `isClosed`, `isRunning` | The state of the context. |

`AnnotationConfigApplicationContext` adds `registerBean<T>(supplier, {...})`, with the options of [BeanRegistrar](bean-registrar.md), and three template methods for subclasses: `postProcessBeanFactory`, `onRefresh` and `onClose`.

## In Spring (Java)

```java
var context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("dev");
context.register(AppConfig.class);
context.refresh();
context.registerShutdownHook();
AuthFacade auth = context.getBean(AuthFacade.class);
context.publishEvent(new UserLoggedIn("ada"));
```

Differences that matter:

- The context is built from generated `BeanModule`s, not from classes or packages scanned at startup.
- `refresh()` checks the whole bean graph before any bean is created. Spring finds missing beans and cycles only while creating them.
- `refreshAsync()` and `closeAsync()` wait for init and destroy callbacks that return a `Future`. Spring has no asynchronous callbacks.
- `getBean<T>({qualifier})` replaces `getBean(name, Class)`, and `getBeanByName(name)` replaces `getBean(String)`. Dart has no overloads.
- `addListener<E>` returns a registration handle to remove the listener.
- Locales are strings such as `'de'`, not `Locale` objects.

## See also

- [The container and beans](index.md)
- [BeanModule](bean-module.md)
- [Lifecycle and SmartLifecycle](lifecycle.md)
- [ConfigurableListableBeanFactory](configurable-listable-bean-factory.md)
- [Aware interfaces](aware.md) (`ApplicationContextAware`)
- [Context events](../events/context-events.md)
- [Events](../events/index.md)
- [Messages](../messages/index.md)
- [Resources](../resources/index.md)
- [Environment](../config/environment.md)
