Backend Development 9 min read

Master Spring Boot 3 Conditional Annotations with Real‑World Examples

This article introduces a continuously updated Spring Boot 3 case collection and PDF e‑book, then dives into the @Conditional annotation, custom condition interfaces, parameterized enhancements, SpringBootCondition usage, and multi‑condition combinations, providing complete code examples and test results.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Master Spring Boot 3 Conditional Annotations with Real‑World Examples

Spring Boot 3 Practical Case Collection

The collection now contains over 90 practical articles and a PDF e‑book with 94 cases, continuously updated for subscribers, who also receive the source code.

1. Introduction

@Conditional is a powerful annotation introduced in Spring 4.0 that lets developers decide whether to create a bean based on conditions such as environment, properties, classpath, or custom logic. It is usually used together with @Configuration and @Bean , and Spring Boot provides derived annotations like @ConditionalOnProperty , @ConditionalOnBean , @ConditionalOnClass .

2. Practical Cases

2.1 Custom Condition Interface

Define a condition that checks a property pack.api.enabled before registering a bean.

<code>public class EnvCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment env = context.getEnvironment();
        return "true".equals(env.getProperty("pack.api.enabled"));
    }
}
</code>

Custom annotation:

<code>@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(ApiCondition.class)
public @interface ConditionalOnApi {}
</code>

Test controller:

<code>@RestController
@RequestMapping("/api")
@ConditionalOnApi
public class ApiController {
    @PostConstruct
    public void init() {
        System.err.println("ApiController init...");
    }
}
</code>

When the property is not set, no output appears; setting pack.api.enabled=true registers the bean.

2.2 Parameterized Enhancement

Make the condition configurable via an annotation attribute.

<code>public @interface ConditionalOnApi {
    String value();
}
</code>
<code>public class ApiCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Map<String, Object> attrs = metadata.getAnnotationAttributes(ConditionalOnApi.class.getName());
        String key = (String) attrs.get("value");
        Environment env = context.getEnvironment();
        return "true".equals(env.getProperty(key));
    }
}
</code>

Usage:

<code>@ConditionalOnApi("pack.api.enabled")
public class ApiController {}
</code>

2.3 Using SpringBootCondition

Extending SpringBootCondition provides logging and richer matching logic.

<code>public class ApiMonitorCondition extends SpringBootCondition {
    private static final ConditionMessage.Builder message = ConditionMessage.forCondition("API Monitor");
    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String monitorEnabled = context.getEnvironment().getProperty("pack.api.monitor.enabled");
        if ("true".equals(monitorEnabled)) {
            return ConditionOutcome.match(message.available("开启API监控功能"));
        }
        return ConditionOutcome.noMatch(message.because("API监控功能关闭"));
    }
}
</code>

Custom annotation and usage:

<code>@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(ApiMonitorCondition.class)
public @interface ConditionalOnApiMonitor {}
</code>
<code>@Configuration
@ConditionalOnApiMonitor
public class ApiMonitorConfig {}
</code>

2.4 Multiple Condition Combination

Combine property, class, and bean existence checks in a single condition.

<code>public class ApiMonitorCondition extends SpringBootCondition {
    private static final ConditionMessage.Builder message = ConditionMessage.forCondition("API Monitor");
    private static final String CLASS_NAME = "com.pack.condition.test.MonitorComponent";
    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String monitorEnabled = context.getEnvironment().getProperty("pack.api.monitor.enabled");
        boolean enabled = "true".equals(monitorEnabled);
        boolean isPresent = isPresent(CLASS_NAME, context.getClassLoader());
        if (enabled) {
            if (isPresent) {
                try {
                    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
                    if (beanFactory.containsBean("monitorComponent")) {
                        return ConditionOutcome.match(message.available("开启API监控功能"));
                    }
                    return ConditionOutcome.noMatch(message.because("容器不存在beanName=monitorComponent的Bean对象"));
                } catch (Exception e) {
                    return ConditionOutcome.noMatch(message.because("容器不存在【" + CLASS_NAME + "】类型的Bean"));
                }
            } else {
                return ConditionOutcome.match(message.because("API监控未能开启缺少【" + CLASS_NAME + "】类"));
            }
        } else {
            return ConditionOutcome.noMatch(message.because("API监控功能关闭"));
        }
    }
    private static boolean isPresent(String className, ClassLoader classLoader) {
        try {
            resolve(className, classLoader);
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }
    private static Class<?> resolve(String className, ClassLoader classLoader) throws ClassNotFoundException {
        return classLoader != null ? Class.forName(className, false, classLoader) : Class.forName(className);
    }
}
</code>

Testing shows appropriate console messages for each scenario.

... (additional images omitted for brevity) ...

backendJavaSpring BootCustom Annotationconditional
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login 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.