В какой момент происходит регистрация бина
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Момент регистрации бина в 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, которая происходит:
- В Spring Boot — в методе
SpringApplication.run() - Для Singleton — сразу же, при инициализации контекста
- Для Prototype — при каждом запросе
getBean() - С @Lazy — при первом запросе, а не при инициализации контекста
После инициализации контекста все Singleton бины готовы к использованию, а Prototype и Lazy бины создаются по требованию.