Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Контексты в Spring: сколько их может быть? И должно ли быть много?
Это хороший архитектурный вопрос, который показывает, понимаю ли я иерархию контекстов в Spring. Дам полный ответ.
Теоретически: ограничений нет
Spring позволяет создавать неограниченное количество контекстов:
ApplicationContext context1 = new AnnotationConfigApplicationContext(Config1.class);
ApplicationContext context2 = new AnnotationConfigApplicationContext(Config2.class);
ApplicationContext context3 = new AnnotationConfigApplicationContext(Config3.class);
// И так далее... нет лимита
Каждый контекст:
- Имеет свой набор бинов
- Может иметь parent контекст
- Может быть независимым
На практике: иерархия контекстов
Однако, в реальных приложениях обычно несколько уровней:
Типичная структура (3 уровня)
Root Application Context (из ContextLoaderListener)
│
├─ Bean definitions
│ ├─ DataSource
│ ├─ UserRepository
│ ├─ UserService
│ ├─ OrderService
│ └─ Transactional interceptors
│
└─ DispatcherServlet Context (Web Context)
└─ Bean definitions
├─ Controllers
├─ View Resolvers
├─ Interceptors
└─ MessageConverters
Это 2 контекста - root и dispatcher.
Практические примеры иерархий
Пример 1: REST приложение с Spring Boot
// Spring Boot создаёт ОДН контекст
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
// Создаётся 1 ApplicationContext
// В нём ВСЕ бины: controllers, services, repositories
}
}
Это самый простой случай: 1 контекст.
Пример 2: Traditional Spring с web.xml
<!-- web.xml -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:dispatcher-servlet.xml</param-value>
</init-param>
</servlet>
Это 2 контекста: root + dispatcher.
Пример 3: Несколько DispatcherServlets
Если приложение имеет несколько DispatcherServlets:
<servlet>
<servlet-name>api</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:api-servlet.xml</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>web</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:web-servlet.xml</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>admin</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:admin-servlet.xml</param-value>
</init-param>
</servlet>
Это 4 контекста: 1 root + 3 dispatcher.
Правило: Сколько контекстов ДОЛЖНО быть?
Modern подход (Spring Boot)
Должно быть: 1 контекст
Всё в одном контексте:
@SpringBootApplication
@ComponentScan(basePackages = "com.example")
public class Application {}
Это проще, быстрее, понятнее.
Traditional подход (классический Spring)
Должно быть: 2 контекста
Root Context (сервисы, репозитории, инфраструктура)
|
└─ Dispatcher Context (контроллеры, MVC конфиг)
Почему 2?
- Разделение ответственности: бизнес-логика в root, web-слой в dispatcher
- Переиспользование: если будет несколько DispatcherServlets, они все видят root контекст
- Testing: легче тестировать без web контекста
Когда нужно несколько контекстов?
Сценарий 1: Разные API endpoints
Root Context (общие бины)
|
├─ API v1 Context (/api/v1/*)
├─ API v2 Context (/api/v2/*)
├─ Admin Context (/admin/*)
└─ Public Context (/) // например, статические страницы
Это имеет смысл, если у каждого API разные requirements:
- Разные interceptors
- Разные message converters
- Разная security конфигурация
Сценарий 2: Встроенный web server + batch processing
Root Context (DataSource, Services)
|
├─ Web Context (DispatcherServlet, Controllers)
└─ Batch Context (для batch jobs)
Это для приложений, которые:
- Имеют web интерфейс
- Но также запускают batch jobs
- И хотят переиспользовать сервисы
На практике: мой опыт
Проект 1: Spring Boot REST API
Контекстов: 1
@SpringBootApplication
public class ApiApplication {}
Всё просто. Легко деплоить, тестировать.
Проект 2: Traditional Spring Web Application
Контекстов: 2
Root (applicationContext.xml):
- DataSource
- UserService
- OrderService
- Transaction Manager
Dispatcher (dispatcher-servlet.xml):
- Controllers
- View Resolver
- Interceptors
Проект 3: Legacy система с множеством сервлетов
Контекстов: 5
Root (общие бины)
|
├─ API Dispatcher
├─ Web Dispatcher
├─ Admin Dispatcher
└─ (старый JSP сервлет)
Это было плохое решение. Слишком сложно для поддержки.
Лучше всего: минимизировать количество контекстов
Правило
1 контекст (Spring Boot) > 2 контекста (traditional) > 3+ контекстов (сложно)
Почему?
- Сложность: каждый контекст добавляет точку отказа
- Производительность: startup time растёт
- Отладка: сложнее понять, какой контекст создал какой бин
- Тестирование: нужно создавать разные контексты для тестов
Как проверить контексты в приложении?
@RestController
@RequestMapping("/debug")
public class DebugController {
@Autowired
private ApplicationContext context;
@GetMapping("/contexts")
public Map<String, Object> showContexts() {
Map<String, Object> result = new HashMap<>();
// Текущий контекст
result.put("current", context.getDisplayName());
// Parent контекст
if (context.getParent() != null) {
result.put("parent", context.getParent().getDisplayName());
}
// Все бины в текущем контексте
result.put("bean_count", context.getBeanDefinitionCount());
result.put("bean_names", context.getBeanDefinitionNames());
return result;
}
}
Вывод
Теоретически: контекстов может быть сколько угодно.
На практике:
- Spring Boot: 1 контекст (оптимально)
- Traditional Spring: 2 контекста (root + dispatcher)
- Сложные системы: 3-5 контекстов (редко)
- Больше 5: переосмотри архитектуру
Мой совет: начни с 1 контекста, и добавляй больше только если есть очень хорошая причина. Обычно 1-2 контекстов достаточно для любого приложения.