Understanding Spring @Conditional and Its Derived Annotations

This article explains how Spring Boot’s @Conditional annotation works, shows how to implement custom Condition classes for language switching, and reviews the suite of derived annotations such as @ConditionalOnBean, @ConditionalOnMissingBean, @ConditionalOnClass, @ConditionalOnMissingClass, and @ConditionalOnProperty with concrete code examples.

Shepherd Advanced Notes
Shepherd Advanced Notes
Shepherd Advanced Notes
Understanding Spring @Conditional and Its Derived Annotations

1. @Conditional

The @Conditional annotation, added in Spring 4, registers a bean only when one or more Condition implementations evaluate to true. Its definition contains a single attribute Class<? extends Condition>[] value() and can be placed on classes or methods.

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
    /**
     * All {@link Condition} classes that must {@link Condition#matches match}
     * in order for the component to be registered.
     */
    Class<? extends Condition>[] value();
}

The Condition interface requires a

boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata)

method; returning true registers the bean, false skips it. The interface is marked @FunctionalInterface, so a lambda can be used.

Example: a multilingual scenario where two custom conditions decide which Language bean to load.

@Data
@Builder
public class Language {
    private Long id;
    private String content;
}
public class ChineseCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment env = context.getEnvironment();
        String prop = env.getProperty("lang");
        return Objects.equals(prop, "zh_CN");
    }
}
public class EnglishCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment env = context.getEnvironment();
        String prop = env.getProperty("lang");
        return Objects.equals(prop, "en_US");
    }
}
@Configuration
public class MyConfig {
    @Bean
    @Conditional(ChineseCondition.class)
    public Language chinese() {
        return Language.builder().id(1L).content("华流才是最屌的").build();
    }

    @Bean
    @Conditional(EnglishCondition.class)
    public Language english() {
        return Language.builder().id(2L).content("english is good").build();
    }

    public static void main(String[] args) {
        System.setProperty("lang", "zh_CN");
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);
        for (String name : ctx.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }
}

Running the program prints chinese, confirming that ChineseCondition returned true and the corresponding bean was injected.

2. Derived @Conditional annotations

2.1 @ConditionalOnBean

Creates a bean only when a specified bean already exists in the context.

@Bean
@ConditionalOnBean(name = "address")
public User user(Address address) {
    // address must be present, otherwise a NullPointerException would occur
    address.setCity("hangzhou");
    address.setId(1L);
    return new User("魅影", address.getCity());
}

2.2 @ConditionalOnMissingBean

Creates a bean only when the specified type is absent.

@Configuration
public class BeanConfig {
    @Bean(name = "notebookPC")
    public Computer computer1() {
        return new Computer("笔记本电脑");
    }

    @ConditionalOnMissingBean(Computer.class)
    @Bean("reservePC")
    public Computer computer2() {
        return new Computer("备用电脑");
    }
}

When no parameters are supplied, the annotation applies only to a @Bean method; the bean type name becomes the default value for the type attribute.

2.3 @ConditionalOnClass

Instantiates the bean if the given class name is present on the classpath.

2.4 @ConditionalOnMissingClass

Instantiates the bean if the given class name is **not** present on the classpath.

2.5 @ConditionalOnProperty

Activates a configuration based on the presence and value of a property.

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {
    // array of property names; cannot be used together with 'value'
    String[] value() default {};
    // prefix for property names, e.g., "spring.http.encoding"
    String prefix() default "";
    // full or partial property names; can be combined with prefix
    String[] name() default {};
    // value to compare against; if equal, the condition matches
    String havingValue() default "";
    // if true, condition matches when property is missing
    boolean matchIfMissing() default false;
    // whether to allow relaxed binding (unknown usage)
    boolean relaxedNames() default true;
}

The condition reads the property from application.properties. If the property is absent, matchIfMissing determines the outcome; otherwise the value is compared with havingValue. If havingValue is not set, any non‑false value enables the bean.

feign:
  hystrix:
    enabled: true

Using the property above, a Feign builder is conditionally created:

@Bean
@Scope("prototype")
@ConditionalOnMissingBean
@ConditionalOnProperty(name = "feign.hystrix.enabled")
public Feign.Builder feignHystrixBuilder() {
    return HystrixFeign.builder();
}

Conclusion : @Conditional and its derived annotations enable Spring Boot to register beans dynamically based on environment properties, classpath contents, or the presence of other beans, forming the core mechanism for conditional configuration.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSpring BootDependency Injection@ConditionalConditionalOnPropertyConditionalOnBean
Shepherd Advanced Notes
Written by

Shepherd Advanced Notes

Dedicated to sharing advanced Java technical insights, daily work snippets, and the power of persistent effort.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.