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

Какие знаешь способы создания контекстов?

2.0 Middle🔥 191 комментариев
#Основы Java

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

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

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

Способы создания контекстов в Spring Framework

Контекст в Spring - это IoC контейнер (ApplicationContext), который управляет жизненным циклом beans и их зависимостями. Это фундаментальная концепция для всех Spring приложений.

1. ApplicationContext - основной способ

Это универсальный интерфейс для создания контекста.

// Самый частый способ в boot приложениях
public static void main(String[] args) {
  ApplicationContext context = SpringApplication.run(Application.class, args);
  
  // Получить bean из контекста
  UserService userService = context.getBean(UserService.class);
  userService.doSomething();
}

2. ClassPathXmlApplicationContext

Олдскул способ с XML конфигурацией.

// Создать контекст из XML файла
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

// Получить bean
UserService userService = context.getBean("userService", UserService.class);

Файл applicationContext.xml:

<beans>
  <bean id="userService" class="com.example.UserService">
    <constructor-arg ref="userRepository"/>
  </bean>
  
  <bean id="userRepository" class="com.example.UserRepository">
    <!-- ... -->
  </bean>
</beans>

3. AnnotationConfigApplicationContext

Способ с Java-конфигурацией (рекомендуется).

// Создать контекст из Java класса конфигурации
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

UserService userService = context.getBean(UserService.class);

AppConfig.java:

@Configuration
public class AppConfig {
  
  @Bean
  public UserRepository userRepository() {
    return new UserRepository();
  }
  
  @Bean
  public UserService userService(UserRepository userRepository) {
    return new UserService(userRepository);
  }
}

Плюсы:

  • Type-safe (проверка типов на compile time)
  • IDE поддержка
  • Простой для рефакторинга

4. SpringApplication (Spring Boot)

Специфичный для Boot способ.

public static void main(String[] args) {
  // Самый удобный способ в Boot приложениях
  SpringApplication app = new SpringApplication(Application.class);
  
  // Можно customизировать
  app.setDefaultProperties(Map.of(
    "server.port", "8080",
    "logging.level.root", "INFO"
  ));
  
  ApplicationContext context = app.run(args);
}

5. Тестовые контексты

Для юнит-тестов используют специальные контексты.

@SpringBootTest  // Создает полный контекст приложения
class UserServiceIntegrationTest {
  
  @Autowired
  private UserService userService;
  
  @Test
  void shouldCreateUser() {
    // userService уже инжектирован из контекста
    User user = userService.create("John");
    assertNotNull(user);
  }
}

@WebMvcTest - минимальный контекст для MVC тестов:

@WebMvcTest(UserController.class)
class UserControllerTest {
  
  @Autowired
  private MockMvc mockMvc;
  
  @MockBean
  private UserService userService;
  
  @Test
  void shouldGetUser() throws Exception {
    when(userService.getUser(1L)).thenReturn(new User("John"));
    
    mockMvc.perform(get("/users/1"))
      .andExpect(status().isOk())
      .andExpect(jsonPath("$.name").value("John"));
  }
}

6. Reactive контекст (для WebFlux)

Для reactive приложений используется более сложный контекст.

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

@RestController
@RequestMapping("/api")
public class UserController {
  
  @GetMapping("/users/{id}")
  public Mono<User> getUser(@PathVariable Long id) {
    // Reactive, non-blocking
    return userService.getUserAsync(id);
  }
}

7. Hierarchical контексты (Parent-Child)

Можно создавать иерархию контекстов.

// Создать parent контекст
ApplicationContext parentContext = 
  new AnnotationConfigApplicationContext(ParentConfig.class);

// Создать child контекст с parent
AnnotationConfigApplicationContext childContext = 
  new AnnotationConfigApplicationContext();
childContext.setParent(parentContext);
childContext.register(ChildConfig.class);
childContext.refresh();

// Child может получить beans из parent
UserService userService = childContext.getBean(UserService.class);

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

  • Микросервисы со своими контекстами
  • Модульные приложения
  • Когда нужна изоляция beans

8. FileSystemXmlApplicationContext

Чтение XML из файловой системы.

ApplicationContext context = 
  new FileSystemXmlApplicationContext("/etc/spring/config.xml");

9. Programmatic Bean Registration

Динамическая регистрация beans во время runtime.

@Configuration
public class DynamicConfig {
  
  @Bean
  public BeanDefinitionRegistryPostProcessor beanPostProcessor() {
    return registry -> {
      // Динамически регистрировать beans
      RootBeanDefinition definition = new RootBeanDefinition(UserService.class);
      registry.registerBeanDefinition("userService", definition);
    };
  }
}

// Или в коде
public static void main(String[] args) {
  AnnotationConfigApplicationContext context = 
    new AnnotationConfigApplicationContext();
  
  // Программно регистрируем bean
  context.registerBean(UserService.class);
  context.refresh();
  
  UserService userService = context.getBean(UserService.class);
}

10. Conditional Bean Creation

Условная регистрация beans в зависимости от среды.

@Configuration
public class ConditionalConfig {
  
  @Bean
  @ConditionalOnProperty(name = "app.enable-mock", havingValue = "true")
  public UserRepository mockUserRepository() {
    return new MockUserRepository();
  }
  
  @Bean
  @ConditionalOnProperty(name = "app.enable-mock", havingValue = "false", matchIfMissing = true)
  public UserRepository realUserRepository() {
    return new RealUserRepository();
  }
  
  @Bean
  @ConditionalOnClass(ReactiveMongoOperations.class)
  public ReactiveRepository reactiveRepository() {
    return new ReactiveRepository();
  }
}

11. GenericWebApplicationContext

Для веб-приложений без Boot.

public static void main(String[] args) {
  GenericWebApplicationContext context = 
    new GenericWebApplicationContext();
  
  // Регистрируем конфигурацию
  context.registerBean(UserService.class);
  context.refresh();
  
  // Запуск сервера
  TomcatServletWebServerFactory factory = 
    new TomcatServletWebServerFactory();
  // ...
}

12. Контекст с профилями

Отличные контексты для разных окружений.

@Configuration
@Profile("production")
public class ProdConfig {
  @Bean
  public DataSource dataSource() {
    // Production БД
    return createProdDataSource();
  }
}

@Configuration
@Profile("test")
public class TestConfig {
  @Bean
  public DataSource dataSource() {
    // H2 test БД
    return createH2DataSource();
  }
}

// Активировать профиль
public static void main(String[] args) {
  SpringApplication app = new SpringApplication(Application.class);
  app.setAdditionalProfiles("production");
  app.run(args);
}

13. Refresh и Close контекста

Управление жизненным циклом контекста.

public class MyApp implements Closeable {
  
  private ApplicationContext context;
  
  public void start() {
    context = new AnnotationConfigApplicationContext(AppConfig.class);
    // Контекст создан и все beans инициализированы
  }
  
  public void reload() {
    // Перезагрузить конфигурацию (если используется refresh-able контекст)
    if (context instanceof AbstractApplicationContext) {
      ((AbstractApplicationContext) context).refresh();
    }
  }
  
  @Override
  public void close() {
    // Закрыть контекст и вызвать @PreDestroy методы
    if (context instanceof AbstractApplicationContext) {
      ((AbstractApplicationContext) context).close();
    }
  }
}

Практический пример: Multi-Module приложение

// Корневой конфиг
@Configuration
@ComponentScan(basePackages = {
  "com.example.app",
  "com.example.service"
})
public class RootConfig {
  // Общие beans (DataSource, TransactionManager)
}

// Web слой конфиг
@Configuration
@ComponentScan(basePackages = "com.example.web")
public class WebConfig {
  // Web-специфичные beans (Controllers, View resolvers)
}

// Main
public static void main(String[] args) {
  // Создать parent контекст (сервис слой)
  ApplicationContext rootContext = 
    new AnnotationConfigApplicationContext(RootConfig.class);
  
  // Создать child контекст (веб слой)
  AnnotationConfigApplicationContext webContext = 
    new AnnotationConfigApplicationContext();
  webContext.setParent(rootContext);
  webContext.register(WebConfig.class);
  webContext.refresh();
}

Выбор правильного контекста

СценарийРекомендация
Spring Boot приложениеSpringApplication.run()
Unit тесты@SpringBootTest
MVC тесты@WebMvcTest
Standalone Java appAnnotationConfigApplicationContext
Веб приложение (non-Boot)WebApplicationContext
Reactive приложениеСтандартный контекст с WebFlux
Динамическая конфигурацияProgrammatic registration
Разные окруженияProfiles + @Configuration

Best Practices

  1. Используй аннотации вместо XML: Более гибко и type-safe
  2. Минимизируй контекст в тестах: Используй @WebMvcTest, @DataJpaTest вместо @SpringBootTest когда возможно
  3. Избегай создания нескольких контекстов: Используй profiles для разных конфигураций
  4. Правильно управляй жизненным циклом: Закрывай контекст при завершении приложения
  5. Используй @Lazy для тяжелых beans: Отложенная инициализация

Контекст - это сердце Spring приложения. Понимание способов его создания критично для development и troubleshooting!

Какие знаешь способы создания контекстов? | PrepBro