Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Способы создания контекстов в 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 app | AnnotationConfigApplicationContext |
| Веб приложение (non-Boot) | WebApplicationContext |
| Reactive приложение | Стандартный контекст с WebFlux |
| Динамическая конфигурация | Programmatic registration |
| Разные окружения | Profiles + @Configuration |
Best Practices
- Используй аннотации вместо XML: Более гибко и type-safe
- Минимизируй контекст в тестах: Используй @WebMvcTest, @DataJpaTest вместо @SpringBootTest когда возможно
- Избегай создания нескольких контекстов: Используй profiles для разных конфигураций
- Правильно управляй жизненным циклом: Закрывай контекст при завершении приложения
- Используй @Lazy для тяжелых beans: Отложенная инициализация
Контекст - это сердце Spring приложения. Понимание способов его создания критично для development и troubleshooting!