Весна: @Component против @Bean

459

Я понимаю, что @Componentаннотация была введена весной 2.5 для того, чтобы избавиться от определения bean-компонента xml с помощью сканирования classpath.

@Beanбыл представлен весной 3.0 и может использоваться @Configurationдля полного избавления от XML-файла и использования вместо него конфигурации Java.

Было бы возможно повторно использовать @Componentаннотацию вместо введения @Beanаннотации? Насколько я понимаю, конечной целью является создание бобов в обоих случаях.

user1396576
источник
4
Есть ли где-нибудь, где @Bean можно использовать отдельно от класса Configuration?
Willa
@ Вилла Да, есть. Это называется Lite mode. И это не рекомендуется. Смотрите здесь: docs.spring.io/spring/docs/current/spring-framework-reference/…
smwikipedia
9
Я бы подвел итог, сказав, что метод с @beanвозвращает настраиваемый экземпляр Spring Bean, в то время как @componentопределяет класс, который может быть позднее создан движком Spring IoC при необходимости.
Sebas

Ответы:

433

@Componentи @Beanделать две совершенно разные вещи, и не следует путать.

@Component@Serviceи @Repository) используются для автоматического обнаружения и автоматической настройки bean-компонентов с использованием сканирования пути к классам. Существует неявное взаимно-однозначное соответствие между аннотированным классом и компонентом (т. Е. Один компонент на класс). При таком подходе управление проводкой весьма ограничено, поскольку оно чисто декларативное.

@Beanиспользуется для явного объявления одного компонента, а не для того, чтобы Spring делал это автоматически, как указано выше. Он отделяет объявление bean-компонента от определения класса и позволяет вам создавать и настраивать bean-компоненты именно так, как вы выбираете.

Чтобы ответить на ваш вопрос ...

было бы возможно повторно использовать @Componentаннотацию вместо введения @Beanаннотации?

Конечно, наверное; но они решили не делать этого, так как они совершенно разные. Весна уже достаточно запутанна, не мутит воду дальше.

skaffman
источник
3
Так что я могу использовать только @Componentтогда, когда требуется автопроводка? Кажется, @Beanне может повлиять@Autowired
Jaskey
3
используйте '@component' для классов, основанных на сервисе, '@Bean' как фабрику более специализированных объектов, например, источник данных jdbc
Junchen Liu
2
@Jaskey вы можете использовать @Autowiredс , @Beanесли вы аннотированный свой класс компонента с@Configuration
starcorn
6
Извините, но я не могу понять ни слова вашего объяснения. Вы четко понимаете это, поэтому, пожалуйста, напишите четкое объяснение или укажите соответствующую документацию?
Алекс Уорден
13
Теперь, когда я понимаю концепцию (из чтения ответов других людей), ваше объяснение имеет смысл. Что еще больше говорит мне, что ваше объяснение бесполезно для тех, кто еще не понимает концепции.
Алекс Уорден
397

@Component Предпочтителен для сканирования компонентов и автоматического подключения.

Когда вы должны использовать @Bean ?

Иногда автоматическая настройка не вариант. Когда? Давайте представим, что вы хотите соединить компоненты из сторонних библиотек (у вас нет исходного кода, поэтому вы не можете аннотировать его классы с помощью @Component), поэтому автоматическая настройка невозможна.

@Bean аннотацию возвращает объект , который пружина должна регистрироваться в качестве боба в контексте приложения. Тело метода несет логику , ответственный за создание экземпляра.

MagGGG
источник
5
Я думаю, что это имеет смысл. Если я правильно понимаю, @Componentидет на сами классы, а @Beanна методы класса (которые дают экземпляры объектов класса).
jocull
182

Давайте рассмотрим, я хочу конкретную реализацию в зависимости от некоторого динамического состояния. @Beanидеально подходит для этого случая.

@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();
    }
}

Однако сделать это невозможно @Component.

outdev
источник
3
Как ты называешь этот пример классом?
PowerFlower
1
@PowerFlower Этот метод должен быть в классе конфигурации, аннотированном@Configuration
Juh_
98
  1. @Component автоматически обнаруживает и настраивает bean-компоненты, используя сканирование пути к классам, тогда как @Bean явно объявляет один bean-компонент, вместо того, чтобы позволить Spring делать это автоматически.
  2. @Component не отделяет объявление bean-компонента от определения класса, а @Bean отделяет объявление bean-компонента от определения класса.
  3. @Component - это аннотация уровня класса, тогда как @Bean - это аннотация уровня метода, а имя метода служит именем компонента.
  4. @Component не нужно использовать с аннотацией @Configuration, где аннотация @Bean должна использоваться внутри класса, аннотируемого @Configuration .
  5. Мы не можем создать bean-компонент класса, используя @Component, если класс находится вне контейнера Spring, тогда как мы можем создать bean-компонент класса, используя @Bean, даже если класс присутствует вне контейнера Spring .
  6. @Component имеет различные специализации, такие как @Controller, @Repository и @Service, тогда как @Bean не имеет специализаций .
Саураб Пракаш
источник
3
4. На самом деле @Bean может быть объявлен в неконфигурационном классе. Это известно как облегченный режим
voipp
1
Что касается пункта 5. Я думаю, что мы поместили боб в контейнер для пружин. Итак, каждый класс находится вне контейнера Spring. Я думаю, пункт 5 должен быть вознагражден
Евгений
97

Оба подхода направлены на регистрацию целевого типа в контейнере Spring.

Разница в том, что @Beanэто применимо к методам , тогда @Componentкак применимо к типам .

Поэтому, когда вы используете @Beanаннотацию, вы управляете логикой создания экземпляра в теле метода (см. Пример выше ). С @Componentаннотацией вы не можете.

Нурлан Акашаев
источник
Что такое тип?
Джей Фрал
20

Я вижу много ответов, и почти везде упомянутый @Component предназначен для автоматического подключения, когда компонент сканируется, а @Bean точно объявляет, что bean-компонент будет использоваться по-другому. Позвольте мне показать, как это отличается.

  • @Bean

Сначала это аннотация уровня метода. Во-вторых, вы обычно используете для настройки bean-компонентов в java-коде (если вы не используете конфигурацию xml), а затем вызываете его из класса, используя метод getBean ApplicationContext. подобно

 @Configuration
class MyConfiguration{
    @Bean
    public User getUser(){
        return new User();
    }
}

class User{
}



//Getting Bean 
User user = applicationContext.getBean("getUser");
  • @Составная часть

Это общий способ аннотировать бин, а не специализированный бин. Аннотация уровня класса и используется, чтобы избежать всей этой вещи конфигурации через конфигурацию java или xml.

Мы получаем что-то вроде этого.

@Component
class User {
}

//to get Bean
@Autowired
User user;

Вот и все . Это было просто введено, чтобы избежать всех шагов конфигурации для создания экземпляра и использования этого компонента.

xpioneer
источник
6
Я думаю, что нет необходимости получать объект User из ApplicationContext, когда вы используете @Beanподход. Вы можете все еще использовать, @Autowireчтобы получить боб, как вы это сделали бы в случае @Component. @Beanпросто добавляет Боб в контейнер Spring, как и @Componentделает. Разница заключается в следующем. 1. Используя @Bean, вы можете добавить сторонние классы в Spring Container. 2. Используя @Bean, вы можете получить желаемую реализацию интерфейса во время выполнения (Используя шаблон фабричного проектирования)
Энди
20

Вы можете использовать, @Beanчтобы сделать существующий сторонний класс доступным для контекста приложения Spring Framework.

@Bean
public ViewResolver viewResolver() {

    InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();

    viewResolver.setPrefix("/WEB-INF/view/");
    viewResolver.setSuffix(".jsp");

    return viewResolver;
}

Используя @Beanаннотацию, вы можете обернуть сторонний класс (он может не иметь @Componentи не может использовать Spring) как бин Spring. И затем, как только он будет обернут, используя @Beanего, он становится одноэлементным объектом и доступен в контексте приложения Spring Framework. Теперь вы можете легко делиться / повторно использовать этот bean-компонент в своем приложении, используя внедрение зависимостей и @Autowired.

Так что думайте о @Beanаннотации как обертке / адаптере для сторонних классов. Вы хотите сделать сторонние классы доступными для контекста приложения Spring Framework.

Используя @Beanприведенный выше код, я явно объявляю один компонент, потому что внутри метода я явно создаю объект с помощью newключевого слова. Я также вручную вызываю методы установки данного класса. Так что я могу изменить значение поля префикса. Так что эта ручная работа называется явным творением. Если я использую @Componentдля того же класса, боб, зарегистрированный в контейнере Spring, будет иметь значение по умолчанию для поля префикса.

С другой стороны, когда мы аннотируем класс с помощью @Component, нам не нужно вручную использовать newключевое слово. Весной он обрабатывается автоматически.

Элвиса
источник
1
Было бы хорошо, если бы этот ответ был обновлен с примером того, как этот бин также используется
softarn
Как бы вы обернули @Bean в сторонний класс, если исходный код не позволяет модификацию?
Веритас
16

Когда вы используете @Componentтег, это то же самое, что иметь POJO (Plain Old Java Object) с методом объявления ванильного компонента (с аннотацией @Bean). Например, следующий метод 1 и 2 даст тот же результат.

Способ 1

@Component
public class SomeClass {

    private int number;

    public SomeClass(Integer theNumber){
        this.number = theNumber.intValue();
    }

    public int getNumber(){
        return this.number;
    }
}

с бобом для 'theNumber':

@Bean
Integer theNumber(){
    return new Integer(3456);
}

Способ 2

//Note: no @Component tag
public class SomeClass {

    private int number;

    public SomeClass(Integer theNumber){
        this.number = theNumber.intValue();
    }

    public int getNumber(){
        return this.number;
    }
}

с бобами для обоих:

@Bean
Integer theNumber(){
    return new Integer(3456);
}

@Bean
SomeClass someClass(Integer theNumber){
    return new SomeClass(theNumber);
}

Метод 2 позволяет вам сохранять объявления bean-компонентов вместе, это немного более гибко и т. Д. Вы можете даже захотеть добавить другой не-vanilla bean-компонент SomeClass, как показано ниже:

@Bean
SomeClass strawberryClass(){
    return new SomeClass(new Integer(1));
}
Какой-то парень
источник
10

У вас есть два способа создания бобов. Одним из них является создание класса с аннотацией @Component. Другой - создать метод и аннотировать его @Bean. Те классы, которые содержат метод с, @Beanдолжны быть аннотированы с @Configuration После того, как вы запустите свой весенний проект, класс с @ComponentScanаннотацией будет сканировать каждый класс, содержащийся @Componentв нем, и восстановит экземпляр этого класса в контейнере Ioc. Еще одна вещь, которую нужно @ComponentScanсделать, - запустить методы с @Beanним и восстановить объект возврата в контейнер Ioc в виде компонента. Поэтому, когда вам нужно решить, какой тип бобов вы хотите создать в зависимости от текущих состояний, вам нужно использовать@Bean, Вы можете написать логику и вернуть нужный объект. Еще одна вещь, которую стоит упомянуть, - это имя метода с @Beanименем по умолчанию для bean-компонента.

Дай Ниу
источник
6
  • @component и его специализации (@Controller, @service, @repository) позволяют автоматически обнаруживать с помощью сканирования путей к классам. Если мы увидим класс компонента, такой как @Controller, @service, @repository будет автоматически сканироваться средой Spring с использованием сканирования компонента.
  • @Bean, с другой стороны, может использоваться только для явного объявления одного компонента в классе конфигурации.
  • @Bean используется для явного объявления одного компонента, а не для того, чтобы Spring делал это автоматически. Это делает отдельное объявление bean-компонента из определения класса.
  • Короче говоря @Controller, @service, @repository предназначены для автоопределения, а @Bean - для создания отдельного компонента из класса.
    - @Controller
    открытый класс LoginController 
    {--code--}

    - @Configuration
    открытый класс AppConfig {
    @Bean
    public SessionFactory sessionFactory () 
    {--code--}
Alok
источник
3

@Bean был создан, чтобы не связывать Spring и ваши бизнес-правила во время компиляции. Это означает, что вы можете повторно использовать свои бизнес-правила в других средах, таких как PlayFramework или JEE.

Более того, у вас есть полный контроль над тем, как создавать bean-компоненты, когда этого недостаточно для стандартной реализации Spring.

Я написал пост об этом.

https://coderstower.com/2019/04/23/factory-methods-decoupling-ioc-container-abstraction/

Даниэль Андрес Пелаес Лопес
источник
3

Разница между Бином и Компонентом:

Разница между Бином и Компонентом

AzarEJ
источник
1

1. О @Component
@Component функционирует аналогично @Configuration.

Они оба указывают, что у аннотированного класса есть одна или несколько бинов, на которые необходимо зарегистрироваться Spring-IOC-Container.

Класс, аннотируемый @Component, мы называем это Component of Spring. Это концепция, которая содержит несколько бобов.

Component classSpring должен быть автоматически отсканирован для регистрации этих компонентов component class.

2. О @Bean
@Bean используется для аннотирования метода component-class(как упомянуто выше). Это указывает на то, что экземпляр, восстановленный аннотированным методом, должен быть зарегистрирован Spring-IOC-Container.

3. Заключение
Разница между ними относительно очевидна, они используются в different circumstances. Общее использование:

    // @Configuration is implemented by @Component
    @Configuration
    public ComponentClass {

      @Bean
      public FirstBean FirstBeanMethod() {
        return new FirstBean();
      }

      @Bean
      public SecondBean SecondBeanMethod() {
        return new SecondBean();
      }
    }
Martin521Wang
источник
0

Дополнительные очки сверху ответы

Допустим, у нас есть модуль, который используется несколькими приложениями и содержит несколько сервисов. Не все нужны для каждого приложения.

Если использовать @Component для этих классов обслуживания и компонент сканирования в приложении,

мы могли бы в конечном итоге обнаружить больше бобов, чем необходимо

В этом случае вам либо пришлось настроить фильтрацию сканирования компонента, либо предоставить конфигурацию, которую могут запускать даже неиспользуемые компоненты. В противном случае контекст приложения не запустится.

В этом случае лучше работать с аннотацией @Bean и создавать только эти компоненты,

которые требуются индивидуально в каждом приложении

Поэтому, по сути, используйте @Bean для добавления сторонних классов в контекст. И @Component, если он только внутри вашего приложения.

AzarEJ
источник