@Configuration

@Configuration() marks a class whose @Bean methods create beans.

Why

Some objects cannot carry @Component():

A configuration class groups the methods that create such objects. Each @Bean method returns one bean, and its parameters are injected like constructor parameters. The configuration class is a bean too.

If every object of yours can carry @Component(), you do not need a configuration class.

Calls between @Bean methods

By default (proxyBeanMethods: true) the container creates a generated subclass of your configuration class. Its @Bean methods return the container's bean. So when one @Bean method calls another, it gets the existing singleton, not a second object. A prototype-scoped @Bean still gives a new instance per call. Static @Bean methods are not intercepted.

Because of the subclass, a class with instance @Bean methods must be extendable from another library: not final, sealed or interface, with a public generative constructor. Otherwise the build fails.

With proxyBeanMethods: false ("lite" mode) the methods run as written and there is no subclass. Then take other beans as method parameters instead of calling the other methods.

@Lazy, @Profile and conditions on the class apply to all its @Bean methods, unless a method says otherwise (@Lazy(false)).

Example

import 'package:spring_core_dart/spring_core_dart.dart';

// Classes from "another package": they cannot be annotated.
class Connection {
  Connection(this.url);
  final String url;
  void connect() {}
  void close() {}
}

class UserStore {
  UserStore(this.connection);
  final Connection connection;
}

abstract interface class Clock {
  DateTime now();
}

class SystemClock implements Clock {
  @override
  DateTime now() => DateTime.now();
}

class Scheduler {
  Scheduler(this.clock);
  final Clock clock;
}

@Configuration()
class DataConfig {
  // The URL comes from the configuration. connect() runs once the
  // bean is created; close() is called at shutdown (inferred).
  @Bean(initMethod: 'connect')
  Connection connection(@Value(r'${db.url}') String url) => Connection(url);

  // The Connection bean is injected as a parameter.
  @Bean()
  UserStore userStore(Connection connection) => UserStore(connection);

  @Bean()
  Clock clock() => SystemClock();

  // Calling clock() returns the container's singleton, not a new clock.
  @Bean()
  Scheduler scheduler() => Scheduler(clock());
}

// Lite mode: no generated subclass. Dependencies come in as parameters.
@Configuration(proxyBeanMethods: false)
class LiteConfig {
  @Bean()
  Scheduler backupScheduler(Clock clock) => Scheduler(clock);
}

Parameters

Name Type Default Meaning
name String? null The bean name of the configuration class. null gives the class name in lowerCamelCase. Named, unlike @Component's positional name.
proxyBeanMethods bool true Whether a generated subclass makes @Bean methods return the container's beans. With false the methods are called as written.

In Spring (Java)

@Configuration
class DataConfig {
  @Bean(initMethod = "connect")
  Connection connection(@Value("${db.url}") String url) {
    return new Connection(url);
  }

  @Bean
  UserStore userStore(Connection connection) {
    return new UserStore(connection);
  }

  @Bean Clock clock() { return new SystemClock(); }

  @Bean Scheduler scheduler() { return new Scheduler(clock()); }
}

@Configuration(proxyBeanMethods = false)
class LiteConfig { ... }

Differences that matter:

See also