@Conditional

@Conditional([...]) registers a bean only when every listed Condition matches.

Why

Use it when the rule is not a profile: a property combination, a file present, another bean missing, the platform. The conditions run while the bean definitions load, before any bean is created. When one does not match, the bean is not registered at all, as if it had no annotation.

A condition is a class that implements Condition:

abstract interface class Condition {
  bool matches(ConditionContext context);
}

ConditionContext gives access to:

Member What it is
environment Properties (including @PropertySource files loaded so far) and active profiles.
registry The bean definitions registered so far.
beanFactory The same factory, for questions by type (getBeanNamesForType).
resourceLoader Finds files, for a condition that depends on one.
definition The bean definition being decided, with its annotations; null for a @PropertySource.

A condition must not create beans. It only sees the definitions registered before it.

There are three ways to attach a condition:

  1. @Conditional([MyCondition]): the class needs a no-argument constructor.
  2. A const annotation class that implements Condition. It is evaluated directly, so it can take arguments. Spring Boot's @ConditionalOnProperty works this way.
  3. A subclass of Conditional that names a set of conditions once.

For conditions on other beans, implement ConfigurationCondition and choose ConfigurationPhase.registerBean. The condition is then decided after the earlier classes have registered their beans.

Example

import 'package:spring_core_dart/spring_core_dart.dart';

// A rule without arguments, used through @Conditional.
class OnAuditEnabled implements Condition {
  const OnAuditEnabled();

  @override
  bool matches(ConditionContext context) =>
      context.environment.getProperty('audit.enabled') == 'true';
}

// Only when `audit.enabled=true` is configured.
@Component()
@Conditional([OnAuditEnabled])
class AuditTrail {}

// A rule with an argument: a const class that implements Condition,
// used directly as an annotation.
class OnProperty implements Condition {
  const OnProperty(this.name, {this.havingValue = 'true'});

  final String name;
  final String havingValue;

  @override
  bool matches(ConditionContext context) =>
      context.environment.getProperty(name) == havingValue;
}

@Component()
@OnProperty('feature.export')
class ExportFeature {}

// Registered only when no other bean named `cache` was declared before.
class OnMissingCache implements Condition {
  const OnMissingCache();

  @override
  bool matches(ConditionContext context) =>
      !context.registry.containsBeanDefinition('cache');
}

class MemoryCache {
  final entries = <String, Object>{};
}

@Configuration()
class CacheConfig {
  @Bean()
  @Conditional([OnMissingCache])
  MemoryCache cache() => MemoryCache();
}

Parameters

Name Type Default Meaning
value (positional) List<Type> required Condition implementations that all have to match. Each needs a no-argument constructor.

In Spring (Java)

class OnAuditEnabled implements Condition {
  public boolean matches(ConditionContext ctx, AnnotatedTypeMetadata m) {
    return "true".equals(ctx.getEnvironment().getProperty("audit.enabled"));
  }
}

@Component
@Conditional(OnAuditEnabled.class)
class AuditTrail {}

Differences that matter:

See also