Как Spring IoC контейнер управляет порядком инициализации бинов?

«Как Spring IoC контейнер управляет порядком инициализации бинов?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Spring определяет порядок создания и инициализации бинов на основе их явных и неявных зависимостей, используя Directed Acyclic Graph (DAG).

Основные механизмы управления порядком:

  1. Неявный порядок через зависимости (Dependency Injection): Spring сначала создает бины, от которых зависят другие.

    @Service
    class ServiceA { /* зависит от BeanB */ }
    @Component
    class BeanB { }
    // Spring создаст BeanB, затем ServiceA.
  2. Аннотация @DependsOn: Явно указывает, что бин зависит от других бинов, даже если нет прямой инъекции.

    @Service
    @DependsOn({"databaseInitializer", "cacheManager"}) // Сначала инициализируются эти бины
    public class UserService { ... }
  3. Интерфейсы жизненного цикла:

    • SmartLifecycle: Позволяет управлять порядком через getPhase(). Бины с меньшей фазой запускаются раньше, а останавливаются позже.
    • @PostConstruct: Метод, аннотированный @PostConstruct, выполняется после инъекции всех зависимостей, но до того, как бин будет готов к использованию.
  4. @Order и Ordered: Не влияют на порядок создания бинов! Они определяют порядок в коллекциях (например, список HandlerInterceptor или Aspect), когда Spring инжектирует List<SomeInterface>.

Важно: Spring может использовать ленивую инициализацию (@Lazy) или проксирование для разрешения циклических зависимостей, но такая архитектура считается антипаттерном.