SoFunction
Updated on 2025-04-14

Detailed explanation of four commonly used conditional assembly techniques in SpringBoot

Spring Boot provides a variety of conditional assembly technologies, allowing developers to dynamically configure applications according to different conditions, greatly improving application flexibility. This article will introduce four commonly used conditional assembly technologies in Spring Boot.

1. @Conditional annotation and derived annotation

1. Basic Principles

@ConditionalAnnotations are the core conditional assembly mechanism introduced by Spring 4. It allows developers to decide whether to create a bean or enable a configuration based on specific conditions.

@ConditionalThe basic working principle is: when Spring container processing is@ConditionalWhen defining the bean of the annotation, the specified condition will be evaluated first. Only when the condition is met will the bean or application configuration be created.

2. @Conditional Basic Usage

use@ConditionalWhen annotating, you need to specify an implementationConditionConditional classes for interfaces:

public interface Condition {
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

Custom condition class example:

public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment env = ();
        String os = ("");
        return os != null && ().contains("linux");
    }
}

public class WindowsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment env = ();
        String os = ("");
        return os != null && ().contains("windows");
    }
}

Then, use these conditional classes to determine the creation of the bean:

@Configuration
public class OperatingSystemConfig {

    @Bean
    @Conditional()
    public CommandService linuxCommandService() {
        return new LinuxCommandService();
    }

    @Bean
    @Conditional()
    public CommandService windowsCommandService() {
        return new WindowsCommandService();
    }
}

The above configuration will create different operating system types according to the operating environment.CommandServiceaccomplish.

3. Commonly used derivative annotations

Spring Boot provides a series of@ConditionalThe derived annotation simplifies the configuration of common condition judgments:

@ConditionalOnClass/@ConditionalOnMissingClass

Determine the configuration based on whether there is a specific class in the classpath:

@Configuration
public class JpaConfig {

    @Bean
    @ConditionalOnClass(name = "")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        // This bean is created only if there is a JPA-related class in the classpath        return new LocalContainerEntityManagerFactoryBean();
    }

    @Bean
    @ConditionalOnMissingClass("")
    public JdbcTemplate jdbcTemplate() {
        // When JPA-related classes do not exist in the classpath, use JdbcTemplate        return new JdbcTemplate();
    }
}

@ConditionalOnBean/@ConditionalOnMissingBean

Determine the configuration based on whether there is a specific bean in the container:

@Configuration
public class DataSourceConfig {

    @Bean
    @ConditionalOnMissingBean
    public DataSource defaultDataSource() {
        // Create a default data source when there is no Bean of DataSource in the container        return new EmbeddedDatabaseBuilder()
                .setType(EmbeddedDatabaseType.H2)
                .build();
    }

    @Bean
    @ConditionalOnBean(name = "customDataSourceProperties")
    public DataSource customDataSource(CustomDataSourceProperties properties) {
        // Create a custom data source when there is a bean named customDataSourceProperties        HikariDataSource dataSource = new HikariDataSource();
        (());
        (());
        (());
        return dataSource;
    }
}

@ConditionalOnProperty

Determine the configuration based on the value of the configuration attribute:

@Configuration
public class CacheConfig {

    @Bean
    @ConditionalOnProperty(name = "", havingValue = "redis")
    public CacheManager redisCacheManager() {
        // When the property value is redis, configure the Redis cache manager        return new RedisCacheManager();
    }

    @Bean
    @ConditionalOnProperty(name = "", havingValue = "ehcache")
    public CacheManager ehCacheManager() {
        // When the property value is ehcache, configure the EhCache cache manager        return new EhCacheCacheManager();
    }

    @Bean
    @ConditionalOnProperty(name = "", havingValue = "false", matchIfMissing = true)
    public CacheManager noOpCacheManager() {
        // Use empty operation cache manager when false or not set        return new NoOpCacheManager();
    }
}

@ConditionalOnExpression

Determine the configuration based on the results of the SpEL expression:

@Configuration
public class SecurityConfig {

    @Bean
    @ConditionalOnExpression("${:true} and ${:basic} == 'oauth2'")
    public SecurityFilterChain oauth2SecurityFilterChain(HttpSecurity http) throws Exception {
        // Effective when true and oauth2        return http
                .oauth2Login()
                .and()
                .build();
    }

    @Bean
    @ConditionalOnExpression("${:true} and ${:basic} == 'basic'")
    public SecurityFilterChain basicSecurityFilterChain(HttpSecurity http) throws Exception {
        // Effective when true and basic        return http
                .httpBasic()
                .and()
                .build();
    }
}

@ConditionalOnWebApplication/@ConditionalOnNotWebApplication

Determine the configuration based on whether the application is a web application:

@Configuration
public class ServerConfig {

    @Bean
    @ConditionalOnWebApplication
    public ServletWebServerFactory servletWebServerFactory() {
        // This bean is created only in a web application        return new TomcatServletWebServerFactory();
    }

    @Bean
    @ConditionalOnNotWebApplication
    public ApplicationRunner consoleRunner() {
        // This bean is created only in non-web applications        return args -> ("Running as a console application");
    }
}

4. Practical example: Build applications that adapt to different cache environments

Here is a practical example to show how to use it@ConditionalSeries annotations build an application that can adapt to different cache environments:

@Configuration
public class FlexibleCacheConfiguration {

    @Bean
    @ConditionalOnClass(name = "")
    @ConditionalOnProperty(name = "", havingValue = "redis")
    @ConditionalOnMissingBean()
    public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
         builder = 
            (redisConnectionFactory);
        
        return ();
    }

    @Bean
    @ConditionalOnClass(name = ".")
    @ConditionalOnProperty(name = "", havingValue = "ehcache")
    @ConditionalOnMissingBean()
    public CacheManager ehCacheCacheManager() {
        return new JCacheCacheManager(getJCacheCacheManager());
    }

    @Bean
    @ConditionalOnProperty(
        name = "", 
        havingValue = "simple", 
        matchIfMissing = true
    )
    @ConditionalOnMissingBean()
    public CacheManager simpleCacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        ((
            new ConcurrentMapCache("users"),
            new ConcurrentMapCache("transactions"),
            new ConcurrentMapCache("products")
        ));
        return cacheManager;
    }

    @Bean
    @ConditionalOnProperty(name = "", havingValue = "false")
    @ConditionalOnMissingBean()
    public CacheManager noOpCacheManager() {
        return new NoOpCacheManager();
    }
    
    private  getJCacheCacheManager() {
        // The logic for creating JCache CacheManager...        return null; // The actual code needs to return the real CacheManager    }
}

In the above configuration:

  • If there is a Redis-related class in the classpath and it is configured=redis, then use Redis cache
  • If there is an EhCache-related class in the classpath and it is configured=ehcache, then use EhCache
  • If configured=simpleor if type is not specified, use a simple memory cache
  • If configured=false, then use NoOpCacheManager that does not perform any cache operations

5. Pros and cons analysis

advantage:

  • Flexible and powerful, able to adapt to almost all conditions to judge scenarios
  • Seamless integration with Spring ecosystem
  • Derived annotations simplify configuration of common scenarios
  • Conditional judgment logic is separated from business logic to keep the code clear

shortcoming:

  • Complex conditions can make configuration difficult to understand and debug
  • The order of conditional assembly may affect the final bean definition

2. Profile condition configuration

1. Basic Principles

Profile is another conditional assembly mechanism provided by Spring, which is mainly used to manage the creation of beans by environment (such as development, testing, production). and@ConditionalCompared with Profile, it focuses more on environment distinction and is simpler to configure.

2. Usage of @Profile annotation

use@ProfileAnnotation tags beans or configuration classes, specifying which profiles they are created only when they are activated:

@Configuration
public class DataSourceConfig {

    @Bean
    @Profile("development")
    public DataSource developmentDataSource() {
        return new EmbeddedDatabaseBuilder()
                .setType(EmbeddedDatabaseType.H2)
                .build();
    }

    @Bean
    @Profile("production")
    public DataSource productionDataSource() {
        HikariDataSource dataSource = new HikariDataSource();
        ("jdbc:mysql://localhost:3306/proddb");
        ("produser");
        ("prodpass");
        return dataSource;
    }
}

It can also be applied at the configuration class level@ProfileAnnotation, controls the activation of the entire configuration class:

@Configuration
@Profile("development")
public class DevelopmentConfig {
    // The unique Bean definition of the development environment...}

@Configuration
@Profile("production")
public class ProductionConfig {
    // The unique definition of beans in the production environment...}

3. How to activate Profile

There are several ways to activate a specified Profile:

Through configuration file

existormiddle:

# 
=development

or

# 
spring:
  profiles:
    active: development

Pass command line parameters

java -jar  --=production

Through environment variables

export SPRING_PROFILES_ACTIVE=production
java -jar 

Activate via code

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication();
        ("production");
        (args);
    }
}

4. Profile combination and negation

Spring Boot 2.4 and above provide more flexible Profile expressions:

Using Profile Group

# 
=proddb,prodmq
=devdb,devmq

The above configuration defines two Profile groups: when "production" is activated, "proddb" and "prodmq" are activated at the same time; when "development" is activated, "devdb" and "devmq" are activated at the same time.

Use negative expressions

@Bean
@Profile("!development")
public MonitoringService productionMonitoringService() {
    return new DetailedMonitoringService();
}

The above configuration indicates that all Profiles except "development" will create this bean.

5. Practical example: Profile-based message queue configuration

The following is a practical example to show how to use Profile to configure message queue connections in different environments:

@Configuration
public class MessagingConfig {

    @Bean
    @Profile("local")
    public ConnectionFactory localConnectionFactory() {
        // Local development uses embedded ActiveMQ        return new ActiveMQConnectionFactory("vm://localhost?=false");
    }

    @Bean
    @Profile("dev")
    public ConnectionFactory devConnectionFactory() {
        // The development environment uses RabbitMQ on the development server        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        ("");
        ("dev_user");
        ("dev_pass");
        return connectionFactory;
    }

    @Bean
    @Profile("prod")
    public ConnectionFactory prodConnectionFactory() {
        // Use production-grade RabbitMQ clusters in the production environment        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        (",");
        ("prod_user");
        ("prod_pass");
        // Additional configuration is added in the production environment        (true);
        (true);
        return connectionFactory;
    }

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        // General RabbitTemplate configuration, using the ConnectionFactory corresponding to the current Profile        return new RabbitTemplate(connectionFactory);
    }
}

Combined with configuration files for specific environments:

# 
spring:
  rabbitmq:
    listener:
      simple:
        concurrency: 1
        max-concurrency: 5

# 
spring:
  rabbitmq:
    listener:
      simple:
        concurrency: 5
        max-concurrency: 10

# 
spring:
  rabbitmq:
    listener:
      simple:
        concurrency: 10
        max-concurrency: 50
        retry:
          enabled: true
          initial-interval: 5000
          max-attempts: 3

6. Pros and cons analysis

advantage:

  • Simple and intuitive use, designed specifically for environmental distinction
  • Perfect integration with Spring Boot configuration system
  • Support combination and negative expressions to enhance expression capabilities
  • Profiles can be switched in various ways to adapt to different deployment scenarios

shortcoming:

  • Limited expression ability, not as good as@ConditionalFlexible annotation
  • Mainly based on a predefined naming environment, it has weak ability to handle dynamic conditions

3. Automatic configuration conditions

1. Basic Principles

Automatic configuration is one of the core features of Spring Boot. It allows the framework to automatically configure applications based on conditions such as classpath, existing beans and configuration properties. Automatic configuration of conditions is the basis for implementing this function. It realizes complex condition judgment logic by combining multiple condition annotations.

2. Commonly used automatic configuration condition combination

In Spring Boot's automatic configuration class, you can often see a combination of multiple conditional annotations:

@Configuration
@ConditionalOnClass()
@ConditionalOnMissingBean()
@ConditionalOnProperty(prefix = "", name = "enabled", matchIfMissing = true)
public class DataSourceAutoConfiguration {
    // Automatic configuration of data source...}

The above configuration indicates:

  • Only if the classpath existsDataSourcekind
  • And there is noDataSourceType of bean
  • andWhen the property does not exist or is true
  • This automatic configuration class will be enabled

3. Customize automatic configuration classes

Developers can create their own automatic configuration classes and use conditional annotations to control their activation conditions:

@Configuration
@ConditionalOnClass()
@ConditionalOnMissingBean()
@ConditionalOnProperty(prefix = "mycache", name = "type", havingValue = "redis")
@EnableConfigurationProperties()
public class RedisCacheAutoConfiguration {

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory,
                                   MyCacheProperties properties) {
         builder = 
            (redisConnectionFactory);
        
        if (() > 0) {
            (()
                    .entryTtl((())));
        }
        
        return ();
    }
}

Configure property class:

@ConfigurationProperties(prefix = "mycache")
public class MyCacheProperties {
    
    private String type;
    private int expireTime = 3600;
    
    // getters and setters
}

4. Enable automatic configuration

To enable a custom autoconfiguration class, you need to createMETA-INF/document:

=\

Or in Spring Boot 2.7 and above, you can use itMETA-INF/spring/document:

5. Automatic configuration sequence control

In complex systems, it may be necessary to control the loading order of the automatic configuration class, which can be done by@AutoConfigureBefore@AutoConfigureAfterand@AutoConfigureOrderAnnotation implementation:

@Configuration
@ConditionalOnClass()
@AutoConfigureAfter()
public class JdbcTemplateAutoConfiguration {
    // JDBC template is automatically configured to ensure that it is after the data source is configured}

@Configuration
@ConditionalOnClass()
@AutoConfigureBefore()
public class SecurityAutoConfiguration {
    // The security configuration should be before the Web MVC configuration}

@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
public class EarlyInitAutoConfiguration {
    // The configuration that needs to be initialized first}

6. Practical example: Automatic configuration of custom monitoring system

Here is a practical example to show how to create a pluggable application monitoring component using automatic configuration conditions:

//Configure property class@ConfigurationProperties(prefix = "")
public class MonitoringProperties {
    
    private boolean enabled = true;
    private String type = "jmx";
    private int sampleRate = 10;
    private boolean logMetrics = false;
    
    // getters and setters
}

// Automatic configuration of JMX monitoring@Configuration
@ConditionalOnProperty(prefix = "", name = "enabled", havingValue = "true", matchIfMissing = true)
@ConditionalOnProperty(prefix = "", name = "type", havingValue = "jmx", matchIfMissing = true)
@ConditionalOnClass(name = "")
@EnableConfigurationProperties()
public class JmxMonitoringAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public MetricsCollector metricsCollector(MonitoringProperties properties) {
        JmxMetricsCollector collector = new JmxMetricsCollector();
        (());
        return collector;
    }
    
    @Bean
    @ConditionalOnMissingBean
    public MetricsExporter metricsExporter(MonitoringProperties properties) {
        JmxMetricsExporter exporter = new JmxMetricsExporter();
        (());
        return exporter;
    }
}

// Prometheus monitoring automatic configuration@Configuration
@ConditionalOnProperty(prefix = "", name = "enabled", havingValue = "true")
@ConditionalOnProperty(prefix = "", name = "type", havingValue = "prometheus")
@ConditionalOnClass(name = "")
@EnableConfigurationProperties()
public class PrometheusMonitoringAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public MetricsCollector metricsCollector(MonitoringProperties properties) {
        PrometheusMetricsCollector collector = new PrometheusMetricsCollector();
        (());
        return collector;
    }
    
    @Bean
    @ConditionalOnMissingBean
    public MetricsExporter metricsExporter(MonitoringProperties properties) {
        PrometheusMetricsExporter exporter = new PrometheusMetricsExporter();
        (());
        return exporter;
    }
    
    @Bean
    public CollectorRegistry collectorRegistry() {
        return new CollectorRegistry(true);
    }
    
    @Bean
    public HttpHandler prometheusEndpoint(CollectorRegistry registry) {
        return new PrometheusHttpHandler(registry);
    }
}

// Automatic configuration of log monitoring@Configuration
@ConditionalOnProperty(prefix = "", name = "enabled", havingValue = "true")
@ConditionalOnProperty(prefix = "", name = "type", havingValue = "log")
@EnableConfigurationProperties()
public class LogMonitoringAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public MetricsCollector metricsCollector(MonitoringProperties properties) {
        LogMetricsCollector collector = new LogMetricsCollector();
        (());
        return collector;
    }
    
    @Bean
    @ConditionalOnMissingBean
    public MetricsExporter metricsExporter() {
        return new LogMetricsExporter();
    }
}

META-INF/file:

=\
,\
,\

Example of usage:

# Use JMX to monitor (default)app:
  monitoring:
    enabled: true
    type: jmx
    sample-rate: 5
    log-metrics: true

# Or use Prometheus to monitorapp:
  monitoring:
    enabled: true
    type: prometheus
    sample-rate: 10

# Or use log monitoringapp:
  monitoring:
    enabled: true
    type: log
    sample-rate: 30

# or disable monitoring completelyapp:
  monitoring:
    enabled: false

7. Pros and cons analysis

advantage:

  • Implement the true "convention over configuration" principle
  • It can create pluggable components, greatly improving code reusability
  • Seamless integration with the Spring Boot ecosystem

shortcoming:

  • The learning curve is steep and requires understanding the combination of multiple conditional annotations.
  • Too many automatic configuration classes may increase application startup time
  • Debugging is difficult, and troubleshooting problems requires in-depth understanding of Spring Boot startup mechanism

8. Summary

Conditional assembly technology Core features Main application scenarios Complexity
@Conditional and derivative annotations The most flexible, supports custom conditions Scenarios that require complex conditions to judge middle
Profile conditional configuration Focus on environmental distinction Multi-environment deployment, environment-specific configuration Low
Automatic configuration conditions Combining multiple conditions to achieve automatic configuration Plugable components, framework development high

By rationally utilizing the conditional assembly technology provided by Spring Boot, developers can build flexible and configurable applications to meet the needs of different environments and business scenarios.

This is the end of this article about the detailed explanation of four commonly used conditional assembly technologies in SpringBoot. For more relevant SpringBoot conditional assembly technology content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!