Что такое Spring Bean и как он управляется контейнером
Что проверяют
Понимаете ли вы, что происходит между созданием объекта и моментом, когда он внедрён в ваш сервис, и где при этом появляются прокси. Следом обычно спрашивают, почему @Transactional не срабатывает при вызове метода изнутри того же класса.
Как отвечать
Бин это объект, жизненным циклом которого управляет IoC-контейнер, то есть ApplicationContext поверх BeanFactory. Сначала контейнер собирает BeanDefinition из сканирования (@Component и стереотипы @Service, @Repository, @Controller), из методов @Bean в @Configuration-классах, реже из XML, и только потом создаёт объекты.
Жизненный цикл singleton-бина:
- создание: вызов конструктора, в него же приходят зависимости. Конструкторное внедрение предпочтительно, при единственном конструкторе
@Autowiredне нужен; - внедрение через поля и сеттеры, затем
Aware-интерфейсы вродеBeanNameAware; BeanPostProcessor:postProcessBeforeInitialization,@PostConstructилиafterPropertiesSet(), затемpostProcessAfterInitialization. На последнем шаге вместо оригинала подставляется прокси для@Transactional,@Async, аспектов;- уничтожение: при закрытии контекста
@PreDestroyилиDisposableBean.destroy().
Скоупы: singleton по умолчанию (один на контекст, а не на JVM, создаётся при старте, если нет @Lazy), prototype (новый на каждое получение, destroy-колбэки для него не вызываются), в вебе request, session, application. Со Spring 6 аннотации жизненного цикла берутся из jakarta.annotation. Циклические зависимости Spring Boot с версии 2.6 по умолчанию запрещает, и это повод пересмотреть дизайн, а не включать spring.main.allow-circular-references.
Где спотыкаются
Не знают про прокси. Вызов this.save() из метода того же бина идёт мимо прокси, поэтому @Transactional и @Async на save() молча не работают.
Внедряют prototype в singleton и ждут новый экземпляр на каждый вызов. Он внедрится один раз, свежий объект получают через ObjectProvider или @Lookup.
Считают singleton потокобезопасным. Контейнер гарантирует один экземпляр, а не безопасность: изменяемое поле в сервисе делят все запросы сразу.