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

Может ли быть несколько конфигураций Spring в одном проекте?

1.8 Middle🔥 171 комментариев
#Spring Framework

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

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

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

Несколько конфигураций Spring в одном проекте

Да, абсолютно можно иметь несколько конфигураций Spring в одном проекте, и это очень частая практика в реальных приложениях. Spring специально разработан для поддержки модульной архитектуры с разными конфигурациями для разных контекстов.

Базовое понимание

Kogda Spring приложение стартует, оно может загрузить несколько @Configuration классов, и каждый из них будет вносить свои бины в контейнер:

// Spring загружает все @Configuration классы и мержит их
@SpringBootApplication
public class IkeaBackendApplication {
    public static void main(String[] args) {
        SpringApplication.run(IkeaBackendApplication.class, args);
    }
}

// Spring автоматически найдёт все @Configuration классы
// в пакете приложения и его подпакетах

Способ 1: Разделение конфигураций по функциональности

Это лучшая практика — разделять конфигурации по доменам:

// 1. Конфигурация БД
@Configuration
public class DatabaseConfig {
    
    @Bean
    public DataSource dataSource() {
        return DataSourceBuilder.create()
            .driverClassName("org.postgresql.Driver")
            .url("jdbc:postgresql://localhost:5432/ikea")
            .username("user")
            .password("pass")
            .build();
    }
    
    @Bean
    public JpaTransactionManager transactionManager(EntityManagerFactory emf) {
        return new JpaTransactionManager(emf);
    }
}

// 2. Конфигурация кеширования (Redis)
@Configuration
@EnableCaching
public class CacheConfig {
    
    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory();
    }
    
    @Bean
    public RedisCacheManager cacheManager(LettuceConnectionFactory connectionFactory) {
        return RedisCacheManager.create(connectionFactory);
    }
}

// 3. Конфигурация асинхронной обработки
@Configuration
@EnableAsync
public class AsyncConfig {
    
    @Bean(name = "taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(100);
        executor.setQueueCapacity(500);
        executor.initialize();
        return executor;
    }
}

// 4. Конфигурация безопасности
@Configuration
@EnableWebSecurity
public class SecurityConfig {
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/public/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .httpBasic(Customizer.withDefaults())
            .build();
    }
}

// 5. Конфигурация HTTP клиента
@Configuration
public class HttpClientConfig {
    
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
    
    @Bean
    public WebClient webClient() {
        return WebClient.builder()
            .baseUrl("https://external-api.com")
            .build();
    }
}

Все эти конфигурации Spring автоматически загрузит и создаст бины в едином контейнере.

Способ 2: Конфигурации для разных профилей (Profiles)

Это очень полезно для разных окружений:

// application.yml
spring:
  profiles:
    active: dev

---
spring:
  config:
    activate:
      on-profile: dev
server:
  port: 8080
database:
  url: jdbc:postgresql://localhost:5432/ikea_dev

---
spring:
  config:
    activate:
      on-profile: prod
server:
  port: 8080
database:
  url: jdbc:postgresql://prod-db.internal:5432/ikea

Теперь создаём разные конфигурации для разных профилей:

// Конфигурация для разработки
@Configuration
@Profile("dev")
public class DevConfig {
    
    @Bean
    public DataSource devDataSource() {
        return DataSourceBuilder.create()
            .driverClassName("org.h2.Driver") // In-memory H2 для dev
            .url("jdbc:h2:mem:testdb")
            .username("sa")
            .password("")
            .build();
    }
    
    @Bean
    public CacheManager devCacheManager() {
        return new ConcurrentMapCacheManager("products", "users");
    }
}

// Конфигурация для production
@Configuration
@Profile("prod")
public class ProdConfig {
    
    @Bean
    public DataSource prodDataSource(
        @Value("${database.url}") String url,
        @Value("${database.username}") String username,
        @Value("${database.password}") String password) {
        
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(url);
        config.setUsername(username);
        config.setPassword(password);
        config.setMaximumPoolSize(50); // Production: больше connections
        return new HikariDataSource(config);
    }
    
    @Bean
    public CacheManager prodCacheManager(LettuceConnectionFactory factory) {
        return RedisCacheManager.create(factory); // Redis в production
    }
}

// Конфигурация для тестирования
@Configuration
@Profile("test")
public class TestConfig {
    
    @Bean
    public DataSource testDataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.H2)
            .addScript("classpath:test-data.sql")
            .build();
    }
    
    @Bean
    public UserRepository mockUserRepository() {
        return Mockito.mock(UserRepository.class);
    }
}

Запуск с разными профилями:

# Development
java -jar app.jar --spring.profiles.active=dev

# Production
java -jar app.jar --spring.profiles.active=prod

# Testing
java -jar app.jar --spring.profiles.active=test

# Несколько профилей
java -jar app.jar --spring.profiles.active=prod,metrics,security

Способ 3: Условные конфигурации (@ConditionalOnClass, @ConditionalOnProperty)

// Конфигурация загружается только если в classpath есть Redis
@Configuration
@ConditionalOnClass(RedisTemplate.class)
@EnableCaching
public class RedisConfigIfAvailable {
    
    @Bean
    public RedisTemplate<String, Object> redisTemplate(
        LettuceConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        return template;
    }
}

// Конфигурация загружается если включена в properties
@Configuration
@ConditionalOnProperty(
    name = "features.analytics.enabled",
    havingValue = "true"
)
public class AnalyticsConfig {
    
    @Bean
    public AnalyticsService analyticsService() {
        return new GoogleAnalyticsService();
    }
}

// Конфигурация с условием на класс
@Configuration
@ConditionalOnMissingBean(EmailService.class)
public class DefaultEmailConfig {
    
    @Bean
    public EmailService emailService() {
        return new ConsoleEmailService(); // Mock для dev
    }
}

Способ 4: Импорт других конфигураций (@Import)

// Главная конфигурация импортирует другие
@Configuration
@Import({
    DatabaseConfig.class,
    CacheConfig.class,
    SecurityConfig.class,
    AsyncConfig.class,
    HttpClientConfig.class
})
public class MainApplicationConfig {
    
    // Дополнительные бины
    @Bean
    public ApplicationEventPublisher eventPublisher(ApplicationContext context) {
        return context;
    }
}

@SpringBootApplication
public class IkeaApplication {
    public static void main(String[] args) {
        SpringApplication.run(IkeaApplication.class, args);
    }
}

Способ 5: Модульная архитектура с отдельными контекстами

// Модуль "Товары"
@Configuration
public class ProductModuleConfig {
    
    @Bean
    public ProductService productService(ProductRepository repo) {
        return new ProductService(repo);
    }
    
    @Bean
    public ProductController productController(ProductService service) {
        return new ProductController(service);
    }
}

// Модуль "Заказы"
@Configuration
public class OrderModuleConfig {
    
    @Bean
    public OrderService orderService(
        OrderRepository orderRepo,
        ProductService productService) {
        return new OrderService(orderRepo, productService);
    }
    
    @Bean
    public OrderController orderController(OrderService service) {
        return new OrderController(service);
    }
}

// Главная конфигурация собирает модули
@Configuration
@Import({
    ProductModuleConfig.class,
    OrderModuleConfig.class
})
public class ApplicationModuleConfig {
}

Способ 6: Конфигурация для интеграционных тестов

// Основной контекст
@SpringBootApplication
public class IkeaApplication {}

// Отдельная конфигурация для тестов
@Configuration
public class TestDataConfig {
    
    @Bean
    @Profile("test")
    public CommandLineRunner loadTestData(UserRepository userRepo) {
        return args -> {
            User testUser = new User("test@example.com", "Test User");
            userRepo.save(testUser);
        };
    }
}

// Тест использует оба контекста
@SpringBootTest
@ActiveProfiles("test")
class UserServiceIntegrationTest {
    
    @Autowired
    private UserRepository userRepository;
    
    @Test
    void shouldLoadTestData() {
        List<User> users = userRepository.findAll();
        assertThat(users).isNotEmpty();
    }
}

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

  1. Разделяй по функциональности

    DatabaseConfig.class
    CacheConfig.class
    SecurityConfig.class
    MQConfig.class
    ExternalApiConfig.class
    
  2. Используй профили для разных окружений

    @Profile("dev")
    @Profile("prod")
    @Profile("test")
    
  3. Используй условные конфигурации

    @ConditionalOnClass
    @ConditionalOnProperty
    @ConditionalOnBean
    
  4. Избегай циркулярных зависимостей между конфигурациями

    // ❌ Плохо
    ConfigA → ConfigB → ConfigA
    
    // ✅ Хорошо
    ConfigA ← CommonConfig → ConfigB
    
  5. Импортируй явно для читаемости

    @Import({Config1.class, Config2.class})
    // Лучше чем полагаться на @ComponentScan
    

Итог

Несколько конфигураций Spring в одном проекте — это стандартная и рекомендуемая практика, которая обеспечивает:

  • Модульность
  • Разделение ответственности
  • Гибкость для разных окружений
  • Легкость тестирования
  • Читаемость и поддерживаемость кода

В реальном production проекте обычно бывает 5-10 конфигураций, каждая отвечающая за свою область.

Может ли быть несколько конфигураций Spring в одном проекте? | PrepBro