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

В какой момент происходит регистрация бина

2.0 Middle🔥 191 комментариев
#Spring Boot и Spring Data#Spring Framework

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

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

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

Момент регистрации бина в Spring

Регистрация бина — это процесс, когда Spring узнаёт об объекте, добавляет его в container и делает доступным для использования. Это происходит на этапе инициализации ApplicationContext, но есть несколько важных моментов.

Общий процесс загрузки Spring приложения

1. PARSING             → Spring читает конфигурацию (XML, @Configuration)
2. REGISTRATION        → Регистрирует bean definitions в registry
3. INSTANTIATION       → Создаёт экземпляры бинов
4. DEPENDENCY INJECTION → Внедряет зависимости
5. READY               → Бины готовы к использованию

Этап 1: Parsing (анализ конфигурации)

Спринг читает конфигурацию из разных источников:

// XML конфигурация
// spring-config.xml анализируется
<bean id="userService" class="com.example.UserService" />

// Аннотации анализируются
@Configuration
public class AppConfig {
    @Bean
    public UserService userService() {
        return new UserService();
    }
}

// @Component анализируется
@Service
public class OrderService {
    // Регистрируется автоматически
}

Этап 2: Registration (регистрация бина)

Регистрация бина происходит при инициализации ApplicationContext.

Для Spring Boot приложения:

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        // В этот момент начинает происходить регистрация
        ApplicationContext context = SpringApplication.run(MyApplication.class, args);
        
        // После run() бины уже зарегистрированы
    }
}

Для классического Spring приложения:

public class Main {
    public static void main(String[] args) {
        // XML-based
        // В этот момент начинается регистрация
        ApplicationContext context = 
            new ClassPathXmlApplicationContext("spring-config.xml");
        
        // Или annotation-based
        ApplicationContext context = 
            new AnnotationConfigApplicationContext(AppConfig.class);
    }
}

Детальный процесс регистрации

Шаг 1: Сканирование компонентов (Component Scanning)

@Configuration
@ComponentScan(basePackages = {"com.example.service", "com.example.repository"})
public class AppConfig {
    // Spring будет сканировать указанные пакеты
    // и находить @Component, @Service, @Repository, @Controller
}

Шаг 2: Создание BeanDefinition

Для каждого найденного бина Spring создаёт BeanDefinition — метаинформацию о бине:

public class UserService {}

// Spring создаёт BeanDefinition:
// {
//   "name": "userService",
//   "class": "com.example.UserService",
//   "scope": "singleton",
//   "singleton": true,
//   "init-method": null,
//   "destroy-method": null
// }

Шаг 3: Регистрация в BeanRegistry

BeanDefinition добавляется в BeanRegistry (контейнер бинов):

// Эквивалент того, что делает Spring
BeanRegistry registry = context.getBeanFactory();
BeanDefinition definition = new RootBeanDefinition(UserService.class);
registry.registerBeanDefinition("userService", definition);

Временная линия в Spring Boot

SpringApplication.run()
    ↓
refresh() вызывается
    ↓
prepareBeanFactory()
    ↓
invokeBeanFactoryPostProcessors()
    ↓
registerBeanPostProcessors()
    ↓
finishBeanFactoryInitialization()  ← ЗДЕСЬ регистрируются бины
    ↓
finishRefresh()
    ↓
Контекст готов, бины доступны

Когда точно происходит регистрация

Для Singleton бинов:

@Service
public class UserService {
    public UserService() {
        System.out.println("UserService создан и зарегистрирован");
    }
}

// Вывод при запуске приложения:
// UserService создан и зарегистрирован

Singleton бины создаются при инициализации контекста (eager loading по умолчанию):

public static void main(String[] args) {
    // Момент запуска
    ApplicationContext context = SpringApplication.run(MyApp.class, args);
    // В этот момент уже все @Service, @Repository бины созданы
    
    // Получение бина
    UserService userService = context.getBean(UserService.class);
}

Для Prototype бинов:

@Service
@Scope("prototype") // Новый экземпляр каждый раз
public class RequestService {
    public RequestService() {
        System.out.println("RequestService создан");
    }
}

public static void main(String[] args) {
    ApplicationContext context = SpringApplication.run(MyApp.class, args);
    // RequestService ЕЩЕ НЕ создан
    
    // Создание происходит при запросе
    RequestService service1 = context.getBean(RequestService.class);
    // Вывод: RequestService создан (первый экземпляр)
    
    RequestService service2 = context.getBean(RequestService.class);
    // Вывод: RequestService создан (второй экземпляр)
    
    System.out.println(service1 == service2); // false
}

Контроль момента создания

Lazy initialization (ленивая загрузка)

@Service
@Lazy  // Бин создаётся только при первом запросе
public class HeavyService {
    public HeavyService() {
        System.out.println("HeavyService инициализирован");
        // Дорогостоящие операции
    }
}

public static void main(String[] args) {
    ApplicationContext context = SpringApplication.run(MyApp.class, args);
    // HeavyService ЕЩЁ НЕ создан
    
    HeavyService service = context.getBean(HeavyService.class);
    // Вывод: HeavyService инициализирован (создан в этот момент)
}

Явная регистрация programmatically

@Configuration
public class AppConfig {
    @Bean
    public UserService userService() {
        // Бин создаётся и регистрируется здесь
        return new UserService();
    }
}

Фазы жизненного цикла бина

REGISTRATION (регистрация)
    ↓
INSTANTIATION (создание экземпляра)
    ↓
SETTER INJECTION (внедрение зависимостей через setter)
    ↓
POST-CONSTRUCT (@PostConstruct, afterPropertiesSet())
    ↓
READY (бин готов к использованию)
    ↓
... использование в приложении ...
    ↓
PRE-DESTROY (@PreDestroy, destroy())
    ↓
DESTROYED (бин удалён)

Пример с жизненным циклом

@Service
public class DatabaseService implements InitializingBean, DisposableBean {
    
    private Connection connection;
    
    // Конструктор
    public DatabaseService() {
        System.out.println("1. Конструктор вызван");
    }
    
    // Setter injection
    @Autowired
    public void setConnection(Connection connection) {
        this.connection = connection;
        System.out.println("2. Зависимость внедрена");
    }
    
    // Post-construct
    @PostConstruct
    public void init() {
        System.out.println("3. Инициализация (@PostConstruct)");
        // Подключение к БД, загрузка данных
    }
    
    // Spring вызовет когда контекст готов
    public void doSomething() {
        System.out.println("4. Бин используется");
    }
    
    // Pre-destroy
    @PreDestroy
    public void cleanup() {
        System.out.println("5. Очистка ресурсов (@PreDestroy)");
    }
    
    @Override
    public void destroy() {
        System.out.println("6. Бин удалён");
    }
}

Вывод при запуске:

1. Конструктор вызван
2. Зависимость внедрена
3. Инициализация (@PostConstruct)
4. Бин используется
...
5. Очистка ресурсов (@PreDestroy)
6. Бин удалён

Ключевой момент

Регистрация бина происходит на этапе инициализации ApplicationContext, которая происходит:

  1. В Spring Boot — в методе SpringApplication.run()
  2. Для Singleton — сразу же, при инициализации контекста
  3. Для Prototype — при каждом запросе getBean()
  4. С @Lazy — при первом запросе, а не при инициализации контекста

После инициализации контекста все Singleton бины готовы к использованию, а Prototype и Lazy бины создаются по требованию.

В какой момент происходит регистрация бина | PrepBro