@Qualifier

@Qualifier('...') picks one bean among several of the same type, by a label or a bean name.

Why

When several beans share a type, the container needs to know which one to inject. @Primary gives a default. @Qualifier selects a specific one where the default is not wanted.

It has two sides:

Without any annotation, a parameter named like a bean also selects it: a parameter frenchGreeter gets the bean named frenchGreeter.

Lookups in code take a qualifier too: context.getBean<Greeter>(qualifier: 'fr').

Example

import 'package:spring_core_dart/spring_core_dart.dart';

abstract interface class Greeter {
  String greet(String name);
}

@Component()
@Primary()
class EnglishGreeter implements Greeter {
  @override
  String greet(String name) => 'Hello $name';
}

// Labelled 'fr'.
@Component()
@Qualifier('fr')
class FrenchGreeter implements Greeter {
  @override
  String greet(String name) => 'Bonjour $name';
}

// This page is French, whatever the default greeter is.
@Service()
class Welcome {
  Welcome(@Qualifier('fr') this.greeter);
  final Greeter greeter;
}

// A bean name works as a qualifier too.
@Service()
class Banner {
  @Autowired()
  @Qualifier('englishGreeter')
  late final Greeter greeter;
}

Parameters

Name Type Default Meaning
value (positional) String required The label, or a bean name or alias.

In Spring (Java)

@Component
@Qualifier("fr")
class FrenchGreeter implements Greeter { ... }

@Service
class Welcome {
  Welcome(@Qualifier("fr") Greeter greeter) { ... }
}

Difference that matters: in Spring, a custom qualifier annotation (an annotation meta-annotated with @Qualifier) matches by its type and attributes. Here annotations are not read at run time, so qualifiers match by their value only.

See also