Spring: @Component против @Bean
Я понимаю, что аннотация @Component
была введена в Spring 2.5
для того, чтобы избавиться от определения бинов в XML, используя сканирование классов. Аннотация @Bean
была представлена в Spring 3.0 и может использоваться вместе с @Configuration
, позволяя полностью отказаться от XML-файлов и использовать конфигурацию на Java.
Могло ли быть возможно повторное использование аннотации @Component
вместо введения аннотации @Bean
? Мое понимание заключается в том, что в обоих случаях конечная цель — создание бинов.
5 ответ(ов)
@Component Предпочтительно использовать для сканирования компонентов и автоматического связывания.
Когда следует использовать @Bean?
Иногда автоматическая конфигурация невозможна. Когда именно? Представьте себе ситуацию, когда вам нужно подключить компоненты из сторонних библиотек (у вас нет исходного кода, поэтому вы не можете аннотировать их классы с помощью @Component), и, следовательно, автоматическая конфигурация не осуществляется.
Аннотация @Bean возвращает объект, который Spring должен зарегистрировать как бин в контексте приложения. Тело метода содержит логику, отвечающую за создание экземпляра.
@Component
и @Bean
выполняют достаточно разные функции и не должны путаться.
Аннотация @Component
(а также @Service
и @Repository
) используется для автоматического обнаружения и конфигурации бинов с помощью сканирования класса. Существует неявное сопоставление один-к-одному между аннотированным классом и бином (то есть один бин на класс). Контроль за связыванием довольно ограничен, так как это чисто декларативный подход.
Аннотация @Bean
используется для явного объявления одного бина, вместо того чтобы позволять Spring делать это автоматически, как в случае с @Component
. Она разделяет декларацию бина и определение класса, позволяя вам создавать и настраивать бины именно так, как вы хотите.
Чтобы ответить на ваш вопрос...
было ли бы возможно использовать аннотацию
@Component
вместо введения аннотации@Bean
?
Конечно, вероятно, это было бы возможно; но они выбрали не делать этого, поскольку эти две аннотации существенно различаются. Spring и без того достаточно запутан, чтобы еще больше усложнять ситуацию.
Аннотация @Component автоматически обнаруживает и настраивает бины с помощью сканирования classpath, в то время как аннотация @Bean явно объявляет один бин, не позволяя Spring делать это автоматически.
Аннотация @Component не отделяет декларацию бина от определения класса, тогда как аннотация @Bean отделяет декларацию бина от определения класса.
Аннотация @Component является аннотацией уровня класса, в то время как @Bean — это аннотация уровня метода, и имя метода служит именем бина.
Аннотацию @Component не обязательно использовать с аннотацией @Configuration, тогда как аннотацию @Bean необходимо использовать внутри класса, аннотированного @Configuration.
Мы не можем создать бин класса с помощью @Component, если класс находится вне контейнера Spring, в то время как мы можем создать бин класса с помощью @Bean, даже если класс находится вне контейнера Spring.
Аннотация @Component имеет разные специализации, такие как @Controller, @Repository и @Service, в то время как у аннотации @Bean нет специализаций.
Если вы хотите реализовать конкретное поведение в зависимости от некоторого динамического состояния, то использование аннотации @Bean
в сочетании с @Scope("prototype")
будет идеальным решением.
Пример кода, который вы привели, выглядит следующим образом:
@Bean
@Scope("prototype")
public SomeService someService() {
switch (state) {
case 1:
return new Impl1();
case 2:
return new Impl2();
case 3:
return new Impl3();
default:
return new Impl();
}
}
В этом примере метод someService()
возвращает разные реализации интерфейса SomeService
в зависимости от значения переменной state
. Каждый раз, когда вы запрашиваете бин, будет создаваться новый экземпляр SomeService
, который соответствует текущему состоянию.
Однако, если вы попытаетесь сделать что-то подобное с аннотацией @Component
, то столкнетесь с ограничениями. Аннотация @Component
предназначена для подключения классов к контексту Spring без необходимости явного определения бинов. Но в этом случае Spring не предоставляет возможности динамического выбора реализации, так как бины, аннотированные @Component
, по умолчанию являются одиночными (singleton) и не могут изменять свое состояние после создания.
Таким образом, если вам нужно динамически менять реализацию в зависимости от состояния, лучше использовать @Bean
с @Scope("prototype")
.
Вижу много ответов, и почти во всех упоминается, что @Component
используется для автозаполнения, где компонент сканируется, а @Bean
ровно для того, чтобы объявить, что этот бин будет использоваться иначе. Позвольте показать, как это отличается.
- @Bean
Во-первых, это аннотация на уровне метода.
Во-вторых, вы обычно используете её для конфигурации бинов в Java-коде (если вы не используете XML-конфигурацию) и затем получаете её из класса с помощью метода ApplicationContext.getBean
. Пример:
@Configuration
class MyConfiguration{
@Bean
public User getUser() {
return new User();
}
}
class User{
}
// Получаем бин
User user = applicationContext.getBean("getUser");
- @Component
Это общее способ аннотирования бина, а не специализированного бина. Это аннотация на уровне класса и используется для того, чтобы избежать всей этой конфигурационной работы через Java или XML.
Получается что-то вроде этого:
@Component
class User {
}
// чтобы получить бин
@Autowired
User user;
Вот и всё. Она была введена, чтобы избежать всех этапов конфигурации для инстанцирования и использования этого бина.
Почему поле с @Autowired в Spring оказывается null?
Разница между <context:annotation-config> и <context:component-scan>
Как установить Java 8 на Mac
Почему в RecyclerView отсутствует onItemClickListener()?
Что значит 'synchronized'?