← Назад к вопросам

Для чего нужна @Conditional?

2.0 Middle🔥 61 комментариев
#Spring Boot и Spring Data

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# @Conditional в Spring

Назначение

@Conditional — это аннотация в Spring Framework, которая позволяет условно регистрировать beans только если выполнены определённые условия. Это мощный механизм для создания гибких и модульных приложений.

Основной синтаксис

@Conditional(MyCondition.class)
@Bean
public MyService myService() {
    return new MyService();
}

Когда Spring инициализирует контекст, он проверяет класс условия (который реализует интерфейс Condition). Если метод matches() возвращает true, bean регистрируется. Если false, bean не создаётся.

Создание собственного условия

public class MySQLDatabaseCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String dbType = context.getEnvironment().getProperty("db.type");
        return "mysql".equalsIgnoreCase(dbType);
    }
}

@Configuration
public class DatabaseConfiguration {
    @Conditional(MySQLDatabaseCondition.class)
    @Bean
    public DataSource mysqlDataSource() {
        System.out.println("Creating MySQL DataSource");
        return new HikariDataSource();
    }
}

Встроенные условия

@ConditionalOnProperty

Регистрирует bean если задана определённая property:

@ConditionalOnProperty(
    name = "app.notifications.enabled",
    havingValue = "true"
)
@Bean
public EmailNotificationService emailService() {
    return new EmailNotificationService();
}

@ConditionalOnClass

Регистрирует bean если в classpath присутствует определённый класс:

@ConditionalOnClass(DataSource.class)
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
    return new JdbcTemplate(dataSource);
}

Это полезно в auto-configuration: если приложение использует JDBC, автоматически создаём JdbcTemplate.

@ConditionalOnMissingBean

Регистрирует bean только если в контексте нет другого bean того же типа:

@ConditionalOnMissingBean(CacheManager.class)
@Bean
public CacheManager defaultCacheManager() {
    return new SimpleCacheManager();
}

@ConditionalOnBean

Регистрирует bean только если в контексте есть другой bean определённого типа:

@ConditionalOnBean(DataSource.class)
@Bean
public ConnectionPoolLogger connectionPoolLogger() {
    return new ConnectionPoolLogger();
}

@ConditionalOnExpression

Регистрирует bean если выполнено SpEL выражение:

@ConditionalOnExpression("${feature.advanced.enabled:false} && ${feature.premium.enabled:false}")
@Bean
public AdvancedFeatureService advancedFeature() {
    return new AdvancedFeatureService();
}

Практические примеры

Выбор реализации в зависимости от профиля

public class ProductionEmailCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String[] profiles = context.getEnvironment().getActiveProfiles();
        return Arrays.asList(profiles).contains("production");
    }
}

@Configuration
public class EmailConfiguration {
    @Conditional(ProductionEmailCondition.class)
    @Bean
    public EmailService productionEmailService() {
        return new RealEmailService();
    }
    
    @ConditionalOnProperty(name = "app.profile", havingValue = "development")
    @Bean
    public EmailService developmentEmailService() {
        return new MockEmailService();
    }
}

Условная регистрация с проверкой класса

public class MongoDbCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        try {
            Class.forName("com.mongodb.client.MongoClient");
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }
}

@Configuration
public class NoSQLConfiguration {
    @Conditional(MongoDbCondition.class)
    @Bean
    public MongoTemplate mongoTemplate(MongoClient mongoClient) {
        return new MongoTemplate(mongoClient, "mydb");
    }
}

Комплексное условие

public class CacheCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String cacheEnabled = context.getEnvironment().getProperty("cache.enabled");
        String cacheType = context.getEnvironment().getProperty("cache.type");
        return "true".equalsIgnoreCase(cacheEnabled) && cacheType != null;
    }
}

@Configuration
public class CacheConfiguration {
    @Conditional(CacheCondition.class)
    @Bean
    public CacheManager cacheManager(Environment env) {
        String cacheType = env.getProperty("cache.type");
        switch(cacheType) {
            case "redis":
                return new RedisCacheManager();
            case "memcached":
                return new MemcachedCacheManager();
            default:
                return new SimpleCacheManager();
        }
    }
}

Кейсы использования

Auto-configuration в стартерах

Spring Boot использует @Conditional для auto-configuration:

@Configuration
@ConditionalOnClass({ DataSource.class, JpaRepository.class })
@EnableJpaRepositories
public class JpaRepositoriesAutoConfiguration {
    // ...
}

Feature flagging

@ConditionalOnProperty(
    name = "feature.new-ui.enabled",
    havingValue = "true"
)
@Bean
public UIService newUIService() {
    return new ModernUIService();
}

Выбор реализации по платформе

public class WindowsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String os = System.getProperty("os.name").toLowerCase();
        return os.contains("win");
    }
}

@Configuration
public class PlatformConfiguration {
    @Conditional(WindowsCondition.class)
    @Bean
    public FileSystemWatcher windowsWatcher() {
        return new WindowsFileSystemWatcher();
    }
}

Лучшие практики

  1. Делайте условия явными — название должно описывать условие
  2. Логируйте решения — добавьте логирование для отладки
  3. Используйте встроенные условия когда возможно — @ConditionalOnProperty, @ConditionalOnClass и т.д.
  4. Комбинируйте условия — несколько условий должны быть истинны одновременно

Резюме

@Conditional позволяет:

  • Гибко конфигурировать приложение в зависимости от окружения
  • Модульно организовать код
  • Автоматически регистрировать beans на основе условий
  • Условно включать/выключать функциональность

Это критически важно для написания гибких Spring приложений и создания стартеров, которые работают в разных окружениях.

Для чего нужна @Conditional? | PrepBro