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

Какие знаешь виды @Conditional?

2.3 Middle🔥 141 комментариев
#Spring Framework

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

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

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

Виды @Conditional аннотаций в Spring

@Conditional — это мощный механизм в Spring Boot для условной регистрации Bean'ов. Spring предоставляет множество встроенных аннотаций для различных условий, а также позволяет создавать свои условия.

1. @ConditionalOnClass

Bean регистрируется, если класс присутствует в classpath:

@Configuration
public class MyConfiguration {
    
    // Этот Bean создаётся только если Jackson присутствует в зависимостях
    @Bean
    @ConditionalOnClass(name = "com.fasterxml.jackson.databind.ObjectMapper")
    public JacksonJsonProvider jacksonJsonProvider() {
        return new JacksonJsonProvider();
    }
    
    // Или используя класс напрямую
    @Bean
    @ConditionalOnClass(Jackson2ObjectMapperBuilder.class)
    public ObjectMapper objectMapper() {
        return new ObjectMapper();
    }
}

Когда использовать: Для опциональной интеграции с внешними библиотеками.

2. @ConditionalOnMissingClass

Противоположность @ConditionalOnClass — Bean создаётся, если класса нет:

@Configuration
public class FallbackConfiguration {
    
    // Если Jackson не установлен, используем GSON
    @Bean
    @ConditionalOnMissingClass("com.fasterxml.jackson.databind.ObjectMapper")
    public GsonJsonProvider gsonJsonProvider() {
        return new GsonJsonProvider();
    }
}

3. @ConditionalOnBean

Bean регистрируется, если другой Bean уже существует:

@Configuration
public class DataSourceConfiguration {
    
    // Создаём HikariCP DataSource только если DataSource Bean уже существует
    @Bean
    @ConditionalOnBean(DataSourceProperties.class)
    public DataSource hikariDataSource(DataSourceProperties props) {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(props.getUrl());
        return new HikariDataSource(config);
    }
}

4. @ConditionalOnMissingBean

Bean регистрируется, если другого Bean нет — очень часто используется:

@Configuration
public class RestTemplateConfiguration {
    
    // Если RestTemplate Bean не создан вручную, создаём дефолтный
    @Bean
    @ConditionalOnMissingBean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
    
    // Или указываем конкретный тип
    @Bean
    @ConditionalOnMissingBean(type = "org.springframework.web.client.RestTemplate")
    public RestTemplate defaultRestTemplate() {
        return new RestTemplate(new HttpComponentsClientHttpRequestFactory());
    }
}

5. @ConditionalOnProperty

Bean регистрируется в зависимости от значения property в конфигурационном файле:

# application.yml
app:
  cache:
    enabled: true
    type: redis
@Configuration
public class CacheConfiguration {
    
    // Включаем кэширование только если app.cache.enabled=true
    @Bean
    @ConditionalOnProperty(
        name = "app.cache.enabled",
        havingValue = "true"
    )
    public CacheManager cacheManager() {
        return new RedisCacheManager(...);
    }
    
    // Проверяем наличие и значение property
    @Bean
    @ConditionalOnProperty(
        name = "app.cache.type",
        havingValue = "redis",
        matchIfMissing = false  // Требует наличие property
    )
    public RedisTemplate<String, Object> redisTemplate() {
        return new RedisTemplate<>();
    }
}

6. @ConditionalOnResource

Bean регистрируется, если ресурс (файл) присутствует в classpath:

@Configuration
public class LicenseConfiguration {
    
    // Создаём Bean только если файл лицензии существует
    @Bean
    @ConditionalOnResource(resources = "classpath:license.txt")
    public LicenseValidator licenseValidator() {
        return new LicenseValidator("license.txt");
    }
}

7. @ConditionalOnJava

Bean регистрируется в зависимости от версии Java:

@Configuration
public class JavaVersionConfiguration {
    
    // Используем новый API только на Java 11+
    @Bean
    @ConditionalOnJava(JavaVersion.ELEVEN_OR_NEWER)
    public ModernHttpClient modernHttpClient() {
        return new ModernHttpClient();  // Использует HttpClient из Java 11
    }
    
    // Старый API для Java 8-10
    @Bean
    @ConditionalOnJava(range = Range.UP_TO_INCLUSIVE, value = JavaVersion.TEN)
    public LegacyHttpClient legacyHttpClient() {
        return new LegacyHttpClient();  // Использует HttpURLConnection
    }
}

8. @ConditionalOnWebApplication

Bean регистрируется, если приложение является web-приложением:

@Configuration
@ConditionalOnWebApplication
public class WebSecurityConfiguration {
    
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
        return http.build();
    }
}

9. @ConditionalOnNotWebApplication

Противоположность — Bean для неWeb-приложений:

@Configuration
@ConditionalOnNotWebApplication
public class BatchConfiguration {
    
    @Bean
    public JobLauncher jobLauncher(JobRepository jobRepository) {
        SimpleJobLauncher launcher = new SimpleJobLauncher();
        launcher.setJobRepository(jobRepository);
        return launcher;
    }
}

10. Собственные @Conditional

Можно создавать свои условия реализуя Condition:

// Определяем собственное условие
public class ProductionCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String profile = context.getEnvironment().getProperty("spring.profiles.active");
        return "production".equals(profile);
    }
}

// Создаём свою аннотацию
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Conditional(ProductionCondition.class)
public @interface ConditionalOnProduction {
}

// Используем
@Configuration
@ConditionalOnProduction
public class ProductionConfiguration {
    @Bean
    public AnalyticsService analyticsService() {
        return new ProductionAnalytics();
    }
}

11. @Profile

Связана с условной регистрацией, но через профили:

@Configuration
@Profile("development")
public class DevelopmentConfiguration {
    @Bean
    public DataSource devDataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(H2)
            .build();
    }
}

@Configuration
@Profile("production")
public class ProductionConfiguration {
    @Bean
    public DataSource prodDataSource() {
        return new HikariDataSource(...);
    }
}

12. Комбинирование условий

@Configuration
public class AdvancedConfiguration {
    
    // Все условия должны быть истинны (AND)
    @Bean
    @ConditionalOnClass(DataSource.class)
    @ConditionalOnProperty(
        name = "spring.datasource.enabled",
        havingValue = "true"
    )
    @ConditionalOnMissingBean(DataSource.class)
    public DataSource dataSource() {
        return new HikariDataSource();
    }
}

Практический пример: Auto-configuration

// spring-boot-autoconfigure
@Configuration
@ConditionalOnClass(DataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(
    prefix = "spring.datasource",
    name = "url"
)
public class DataSourceAutoConfiguration {
    
    @Bean
    public DataSource dataSource(DataSourceProperties properties) {
        return createDataSource(properties);
    }
}

Это как Spring Boot автоматически добавляет DataSource, если в pom.xml есть драйвер и в application.yml есть spring.datasource.url.

Порядок применения условий

1. @ConditionalOnClass — classpath
2. @ConditionalOnBean — другие Beans
3. @ConditionalOnProperty — конфигурация
4. @ConditionalOnResource — файлы
5. @ConditionalOnJava — версия JVM
6. Кастомные Condition

Когда использовать

  • @ConditionalOnClass — опциональные библиотеки
  • @ConditionalOnMissingBean — дефолтные реализации
  • @ConditionalOnProperty — включение/отключение функций
  • @Profile — разные конфигурации для разных окружений
  • @ConditionalOnWebApplication — разная конфигурация для Web/Batch

Все эти аннотации работают вместе, создавая гибкую и мощную систему конфигурации в Spring Boot, позволяя автоматически регистрировать нужные Bean'ы в зависимости от контекста приложения.