@PreDestroy

@PreDestroy() marks a method the container calls when a bean is destroyed.

Why

Use it to release what the bean holds: flush a buffer, close a file, cancel a timer, end a subscription.

When it runs:

The method takes no arguments. It may return a Future. closeAsync() waits for it; close() logs it and goes on without waiting.

Errors thrown during destruction are logged and collected. They do not stop the shutdown of the other beans.

The order of destruction for one bean:

  1. DestructionAwareBeanPostProcessor.postProcessBeforeDestruction;
  2. @PreDestroy methods;
  3. DisposableBean.destroy;
  4. the destroyMethod of @Bean (by default an inferred close, shutdown or dispose).

Example

import 'dart:async';
import 'dart:io';

import 'package:spring_core_dart/spring_core_dart.dart';

// Buffers log lines and writes them in batches.
@Component()
class EventBuffer {
  final _lines = <String>[];
  Timer? _timer;

  @PostConstruct()
  void start() =>
      _timer = Timer.periodic(const Duration(seconds: 10), (_) => _write());

  void add(String line) => _lines.add(line);

  void _write() {
    File('events.log').writeAsStringSync(
      _lines.map((l) => '$l\n').join(),
      mode: FileMode.append,
    );
    _lines.clear();
  }

  // Runs on context.close(): nothing is lost at shutdown.
  @PreDestroy()
  void flush() {
    _timer?.cancel();
    _write();
  }
}
void main() {
  final context = ApplicationContext.run([appBeans])
    // Closes the context on Ctrl+C or SIGTERM, so @PreDestroy runs.
    ..registerShutdownHook();
  context.getBean<EventBuffer>().add('started');
}

Parameters

None.

In Spring (Java)

The Jakarta annotation jakarta.annotation.PreDestroy:

@Component
class EventBuffer {
  @PreDestroy
  void flush() { ... }
}

Differences that matter: a Future-returning method is supported and awaited by closeAsync(). registerShutdownHook() reacts to SIGINT and SIGTERM and does nothing on the web.

See also