Hook: This is Spring Boot’s “does the toolbox have this tool?” switch, and interviewers love it because it shows whether you understand optional dependencies instead of just memorizing annotations.
Question: Explain @ConditionalOnClass.
Answer: @ConditionalOnClass is a Spring Boot condition that creates a bean or configuration only when a specific class is present on the classpath, which is the set of libraries your app can see at runtime. It is most often used in auto-configuration so Boot can support optional features like JSON, web, or messaging without failing when those libraries are missing.
Interview-Ready Answer: I use @ConditionalOnClass when I want Spring Boot to enable a feature only if a dependency is available. It checks for the class on the classpath before the bean is created, so the app can start safely even when that library is absent. In practice, Boot auto-configurations use it together with @ConditionalOnMissingBean so the framework backs off if the user has already provided their own bean.
@ConditionalOnClass is a Spring Boot annotation used in auto-configuration and regular configuration to say: “Only activate this bean or config if this type exists.” It is a condition, meaning a rule that must be true before Spring registers the bean definition. This is different from normal @Bean creation, which happens unconditionally once the configuration class is processed.
@ConditionalOnClass is backed by Boot’s internal OnClassCondition, which checks whether each required class name is available to the class loader.@ConditionalOnMissingBean too, so it also avoids overriding a user’s custom bean.Use it when your code depends on an optional library: for example, only wire JSON helpers if Jackson is on the classpath, only create an AMQP adapter if RabbitMQ classes exist, or only enable a cloud integration when the vendor SDK is present. This is one of the core tricks that lets Spring Boot ship many starter modules without forcing every project to pull in every dependency.
| Annotation | Checks | Typical use |
|---|---|---|
@ConditionalOnClass | Type exists | Optional library support |
@ConditionalOnBean | Bean exists | Build on user beans |
@ConditionalOnMissingClass | Type absent | Fallback behavior |
The check is cheap: roughly O(n) in the number of class names listed in the annotation, with each lookup being a fast classpath check. Boot also caches condition evaluation during startup, so this is tiny compared with creating beans or opening network connections. The big gotcha is that value = SomeType.class requires that type to be available at compile time, while name = "com.example.SomeType" lets you avoid a hard dependency on an optional library. Another subtle point: the annotation checks presence, not version or API compatibility, so a class can exist and still be the wrong version for your code.
Version note: the behavior is the same in modern Spring Boot 2.x and 3.x, and it remains a main building block of Boot auto-configuration. The practical rule is simple: if you are integrating with something that may or may not be on the classpath, guard it with @ConditionalOnClass and pair it with a sensible fallback.
Imagine a checkout service that supports Stripe only when the Stripe SDK is installed. With @ConditionalOnClass(name = "com.stripe.Stripe"), Spring Boot creates the Stripe payment adapter only in deployments that include that library. In a test environment or a lightweight internal deployment, the app still starts, and the fallback payment path stays active.
What goes wrong when this is misunderstood: a developer imports the Stripe class directly in a configuration class and forgets the optional dependency is missing in staging. The app crashes during startup with a NoClassDefFoundError, Kubernetes marks the pod as failing, and users see checkout unavailable. In logs, you usually see the failure before the web server finishes booting, which is a strong clue that the problem is classpath-related, not a runtime business bug.
package com.example.conditionalonclass;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@SpringBootApplication
public class ConditionalOnClassDemoApplication implements CommandLineRunner {
private final ApplicationContext context;
public ConditionalOnClassDemoApplication(ApplicationContext context) {
this.context = context;
}
public static void main(String[] args) {
SpringApplication.run(ConditionalOnClassDemoApplication.class, args);
}
@Override
public void run(String... args) {
// If the condition matched, the bean exists; if not, the app still starts.
printBean("featureBean");
printBean("missingFeatureBean");
printBean("fallbackBean");
}
private void printBean(String beanName) {
if (context.containsBean(beanName)) {
System.out.println(beanName + " = " + context.getBean(beanName));
} else {
System.out.println(beanName + " was skipped because its class condition did not match.");
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(name = "com.fasterxml.jackson.databind.ObjectMapper")
static class FeatureConfig {
@Bean
String featureBean() {
// This bean only appears when the optional library is actually on the classpath.
return "Feature enabled: Jackson-like library detected";
}
}
@Configuration(proxyBeanMethods = false)
static class FallbackConfig {
@Bean
String fallbackBean() {
// A normal bean with no condition: always available.
return "Always available fallback";
}
@Bean
@ConditionalOnClass(name = "com.example.optional.DoesNotExist")
String missingFeatureBean() {
// This never runs in a normal app, which is exactly the point:
// the optional integration is skipped instead of breaking startup.
return "You should never see this";
}
}
}
Follow-up & Tricky Questions:
@ConditionalOnClass different from @ConditionalOnBean? @ConditionalOnClass checks the classpath, while @ConditionalOnBean checks the application context for an actual bean instance. One is about available libraries; the other is about already-created Spring beans.@ConditionalOnMissingBean? So Boot can provide a default only when the user has not defined their own bean. This is the “back off” rule that makes Boot auto-configuration polite instead of invasive.name instead of value? Use name when the class may not be on your compile classpath, because value = SomeType.class requires the type to be available to compile. name is the safer choice for truly optional external libraries.@Bean method? Yes. That lets Spring skip only that bean while keeping the rest of the configuration class active, which is useful when one feature is optional but the rest of the module is always needed.ApplicationContextRunner in Boot tests to start a tiny context and assert whether the bean is present. That gives you fast, focused condition tests without launching the whole app.Common Mistakes:
@ConditionalOnClass for libraries and @ConditionalOnBean for Spring beans.value = OptionalType.class for a dependency that may be absent. Correction: use name = "fully.qualified.Type" for optional libraries.Memory Hook: Think: “If the tool is in the toolbox, open the box; if not, leave the room.” The classpath is the toolbox, and @ConditionalOnClass decides whether the box gets opened.
Cheat Sheet:
@ConditionalOnMissingBean.name for truly optional external types.Practice Tasks:
org.h2.Driver is present, then run the app with and without H2.ApplicationContextRunner that asserts featureBean exists when the class is present and disappears when it is not.