In Spring Boot,@Conditional
Annotations are used to conditionally register beans. This means it can decide whether a specific bean should be created based on certain conditions. This annotation can be placed on a configuration class or method, and it will determine whether the corresponding component should be instantiated based on the provided set of conditions.
To use@Conditional
When annotating, it needs to be implementedCondition
Interface and rewritematches
method. This method returns a Boolean value to indicate whether the condition matches. If the condition is true, create a bean; otherwise, create the bean is skipped.
Here is a simple example showing how to use custom conditions:
import ; import ; import ; public class MyCustomCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // Add your conditional logic here // For example, check system properties, environment variables, existing beans, etc. return false; // Return true or false according to conditional logic } }
- ConditionContext: Provides access to the current parsing context, including:
- Environment: It can be used to obtain environment variables, system properties, etc.
- BeanFactory: If available, you can access the registered beans through it.
- ClassLoader: can be used to check whether the class on the classpath exists.
- EvaluationContext: Can be used to evaluate SpEL expressions.
- AnnotatedTypeMetadata provides access to methods or class metadata with annotated, such as annotated property values.
Custom condition class
Suppose we have an application that should decide whether to load a specific bean based on the operating system. We can create a name calledOnWindowsCondition
Conditional class:
import ; import ; import ; public class OnWindowsCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { return "win".equals(().getProperty("").toLowerCase().substring(0, 3)); } }
Then use it in the configuration class:
@Configuration public class MyConfig { @Bean @Conditional() public WindowsSpecificService windowsSpecificService() { return new WindowsSpecificServiceImpl(); } }
Spring Boot provides built-in conditional annotations
@ConditionalOnProperty
When you want to create a bean based on whether the attributes in the configuration file exist or have a specific value, you can use@ConditionalOnProperty
annotation. For example:
@Configuration public class MyConfig { @Bean @ConditionalOnProperty(name = "", havingValue = "true") public MyFeature myFeature() { return new MyFeature(); } }
In this example, only if the configuration file has a name calledThe attribute and its value is
true
Only whenMyFeature
bean。
More usages
- prefix: Specify the attribute name prefix.
- name: Specify the attribute name (can be an array, representing multiple attributes).
- havingValue: Specifies the value that the property must have, the default is an empty string.
-
matchIfMissing: If no attribute is found, the default match or not is:
false
。
For example, you can configure it like this:
@Bean @ConditionalOnProperty(prefix = "app", name = "", havingValue = "true", matchIfMissing = false) public FeatureService featureService() { return new FeatureServiceImpl(); }
This will ensure that only in=true
It will be created only whenFeatureService
bean; if the property is not set andmatchIfMissing=false
, it will not be created.
@ConditionalOnClass and @ConditionalOnMissingClass
These two annotations are used to check whether certain classes exist or do not exist under the classpath. This is very useful when integrating third-party libraries, because you can conditionally register beans related to these libraries. For example:
@Configuration @ConditionalOnClass(name = "") public class ExternalLibraryConfig { // ... }
If there is a classpathExternalLibraryClass
class, this configuration will be applied.
@ConditionalOnBean and @ConditionalOnMissingBean
These annotations are used to decide whether to create a new bean based on whether there is a bean of the specified type in the context. This is very useful for ensuring that beans with the same functionality are not registered repeatedly.
@Bean @ConditionalOnMissingBean() public MyService myService() { return new MyServiceImpl(); }
What this means here is: if there is no type in the context yetMyService
a new bean is createdMyServiceImpl
Instance and register as bean.
@ConditionalOnExpression using SpEL expression
Can be passed@ConditionalOnExpression
To write complex conditional expressions. For example, it is determined whether to create a bean based on multiple attribute combinations or environment variables.
@Bean @ConditionalOnExpression("${:'default'} == 'myapp' && ${env:dev} == 'prod'") public ProdSpecificBean prodSpecificBean() { return new ProdSpecificBean(); }
This code means only if the application name is'myapp'
And environment variablesenv
Set as'prod'
Only whenProdSpecificBean
。
Use scenarios
Dynamic condition evaluation
Sometimes you may need to dynamically adjust the bean's behavior after the application is started based on certain changes (such as user input or the status of external services). Although@Conditional
It is mainly used for static condition judgment at startup, but you can achieve similar effects by combining other mechanisms (such as event listeners, timing tasks, etc.).
@Configuration public class DynamicConditionConfig { private final AtomicBoolean shouldCreateBean = new AtomicBoolean(false); @Bean @ConditionalOnProperty(name = "", havingValue = "true") public MyDynamicBean myDynamicBean() { return () -> (); } // Methods to simulate external trigger update condition status public void updateCondition(boolean value) { (value); } }
In this example,MyDynamicBean
The behavior depends on an atomic boolean variableshouldCreateBean
, This variable can be changed at runtime, affecting the bean's behavior.
Conditioned AOP section
You can also apply conditions to AOP sections for more flexible cross-cutting concern management. For example:
@Aspect @ConditionalOnProperty(name = "", havingValue = "true") public class LoggingAspect { @Around("execution(* .*.*(..))") public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable { long start = (); Object proceed = (); long executionTime = () - start; (().getClass().getName() + "." + ().getName() + " executed in " + executionTime + "ms"); return proceed; } }
This code means only=true
Logging facets will only be activated.
use@Profile
and@Conditional
Combined
Sometimes, you may want to combine@Profile
and@Conditional
to create more granular conditional logic. For example:
@Configuration @Profile("dev") public class DevConfig { @Bean @ConditionalOnProperty(name = "", havingValue = "true") public FeatureX featureX() { return new FeatureXImpl(); } }
What this means here is: only in the development environment (dev
Profile) and=true
Created only whenFeatureX
bean。
Conditional agent
For beans that require delayed initialization or lazy loading, you can consider using@Scope("proxy")
and@Lazy
Combined with comments@Conditional
to implement conditional proxy.
@Bean @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) @Lazy @ConditionalOnProperty(name = "", havingValue = "true") public LazyInitFeature lazyInitFeature() { return new LazyInitFeatureImpl(); }
This ensures that only when the conditions are met and the first visit islazyInitFeature
It will be instantiated only when it is bean.
Debugging Tips
use@PostConstruct
and@PreDestroy
Monitor the bean life cycle
To better understand which beans are created or destroyed, you can add them in the bean class@PostConstruct
and@PreDestroy
method and output log information.
@Component @ConditionalOnProperty(name = "", havingValue = "true") public class FeatureY { @PostConstruct public void init() { ("FeatureY initialized."); } @PreDestroy public void destroy() { ("FeatureY destroyed."); } }
This approach helps track the life cycle of the bean and confirms that the conditions work as expected.
use-mode=off
Reduce interference
When you focus on debugging conditional logic, closing Spring Boot boot banners can help reduce unnecessary output and make logs clearer.
-mode=off
Frequently Asked Questions
Environment properties are not loading correctly
If you find that the conditional annotation does not work as expected, please check whether the environment properties file is loaded correctly (e.g.or
). Make sure these files are in the correct path and contain the required property definitions.
Classpath conflict
Classpath conflict is a common cause when encountering the problem that conditional annotations do not work. Especially when you use@ConditionalOnClass
or@ConditionalOnMissingClass
When , make sure there are no duplicate dependencies in the project. You can use Maven or Gradle commands to analyze dependency trees:
Maven:
mvn dependency:tree
Gradle:
gradle dependencies
Conditional logic error
Carefully review your conditional logic to make sure they meet expectations. The behavior of each condition can be verified by unit testing. For example:
@Test void testFeatureYEnabled() { ApplicationContextRunner runner = new ApplicationContextRunner() .withPropertyValues("=true"); (context -> assertThat(context).hasSingleBean()); } @Test void testFeatureYDisabled() { ApplicationContextRunner runner = new ApplicationContextRunner() .withPropertyValues("=false"); (context -> assertThat(context).doesNotHaveBean()); }
Things to note
- Conditional annotations are only applicable to Spring's configuration phase, so they cannot be used for runtime decisions.
- When used
@Conditional
When annotating other conditionals, please make sure that your conditional logic does not cause circular dependencies or unexpected behavior. - When writing conditional logic, considering the performance impact, try to make conditional judgments lightweight.
This is all about this article about Spring Boot @Conditional annotations. For more related Spring Boot @Conditional annotations, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!