Работа аннотации @Bean в Spring: один или несколько объектов?
Быстрый ответ
Для обеспечения использования singleton-экземпляра бина достаточно обратиться к методу с аннотацией @Bean
в конфигурационном классе Spring. Это даст возможность многократно вызывать уже созданные бины, поддерживая их уникальность в контексте приложения.
@Configuration
public class AppConfig {
@Bean
public MyBean myBean() {
return new MyBean();
}
// Многократное использование экземпляра MyBean как singleton
public void someMethod() {
MyBean bean = myBean();
}
}
Учтите, что прямое обращение к методам соответствует принципам внедрения зависимостей и жизненного цикла в Spring, что позволяет избежать ненужного клонирования объектов.
Если вам необходимо при каждом обращении получать новый экземпляр бина, укажите область видимости "prototype" с помощью аннотации @Scope("prototype")
в методе @Bean
.
@Bean
@Scope("prototype")
public MyBean prototypeBean() {
return new MyBean();
}
Для методов, которым необходимо избежать проксирование, используйте статические методы с аннотацией @Bean
. Это обеспечивает прямое создание экземпляров.
@Bean
public static MyBean alwaysNewBean() {
return new MyBean();
}
Основы проксирования с CGLIB
CGLIB преобразует @Bean
-методы таким образом, чтобы они создавали singleton-экземпляры. Однако это не относится к статическим методам.
@Configuration
public class ProxyConfig {
@Bean
public Service service() {
return new ServiceImpl();
}
public Service createService() {
return service(); // Синглтон и проксирование CGLIB в действии!
}
public static Service createNewService() {
return service(); // Не будет скомпилировано; статические методы не допускают проксирование!
}
}
Непредсказуемые ситуации: сложные паттерны
В случаях сложной инициализационной логики может потребоваться создание нового экземпляра. В этих ситуациях рекомендуется использовать внедрение зависимостей либо метод getBean()
для доступа к бинам с областью видимости "prototype".
При вызове метода @Bean
внутри класса Spring ведет учёт, однако, если нужно обратиться к этому же методу "извне", следует использовать контекст приложения для получения бина.
@Configuration
public class ExternalConfig {
@Autowired
private ApplicationContext context;
public void useBean() {
MyBean bean = context.getBean(MyBean.class); // Корректный вызов singleton-бина
}
}
Визуализация
Представим себе садовника, выбирающего растения из питомника:
👩🌾: "Мне нужен подсолнух 🌻 из моего питомника для устройства переднего двора."
Теперь сравним это с вызовом метода @Bean
в Spring:
@Bean
public Sunflower sunflower() {
return new Sunflower();
}
Сад (🏡): [🌹, 🌷, 🌻, 🌼]
Как и Spring, садовник на организованный манер при каждой необходимости запрашивает новые экземпляры растений.
Оживление вашей конфигурации
Методы с аннотацией @Bean
могут быть объявлены как защищённые, приватные или пакетные, хотя для улучшения читаемости кода рекомендуются публичные. В этих методах использование рефлексии может стать источником проблем из-за ограничений безопасности JVM.
Зная нюансы работы с singleton-областью видимости и аннотацией @Bean
, вы сможете применять различные паттерны проектирования, создавая чистый и легко поддерживаемый код.
Полезные материалы
- Понимание аннотации Spring @Bean — подробный разбор в официальной документации Spring.
- Spring – Конфигурация на Java — глобальный обзор создания бинов в Spring с использованием
@Bean
. - Справочная документация Spring Boot — инструкция по использованию
@Bean
в Spring Boot. - java – Как получить экземпляр класса типа T? – Stack Overflow — обсуждение на StackOverflow о прямых вызовах
@Bean
. - Аннотации Spring | DigitalOcean — понятное руководство по использованию аннотаций Spring.