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

Сколько может быть контекстов?

2.0 Middle🔥 181 комментариев
#Другое

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

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

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

Контексты в 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+ контекстов (сложно)

Почему?

  1. Сложность: каждый контекст добавляет точку отказа
  2. Производительность: startup time растёт
  3. Отладка: сложнее понять, какой контекст создал какой бин
  4. Тестирование: нужно создавать разные контексты для тестов

Как проверить контексты в приложении?

@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 контекстов достаточно для любого приложения.

Сколько может быть контекстов? | PrepBro