Різниця між @Bean та @Autowired


79

Чому я не можу використовувати @Autowiredв цьому випадку?

@SpringBootApplication
public class Application {

    @Autowired
    BookingService bookingService;

    public static void main(String[] args) {
        bookingService.book("Alice", "Bob", "Carol");
    }
}

але можна використовувати @Bean

@SpringBootApplication
public class Application {

    @Bean
    BookingService bookingService() {
        return new BookingService();
    }

    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(Application.class, args);
        BookingService bookingService = ctx.getBean(BookingService.class);
        bookingService.book("Alice", "Bob", "Carol");
    }
}

Хіба не два способи генерувати BookingServiceодне і те ж?


11
Анотація Bean призначена для реєстрації вашого компонента у весняному контексті, тоді як анотація Autowried призначена для отримання компонента з вмісту програми Spring та підключення його як залежності для іншого об'єкта
— prem kumar

Ви також повинні доставити клас BookingService. Тому що, якщо це анотовано Component, то ваш перший клас також буде працювати як другий.
— PowerFlower

Відповіді:


178

@Beanі @Autowiredробити дві дуже різні речі. Інші відповіді тут пояснюються трохи детальніше, але на більш простому рівні:

  • @Bean каже Spring: "ось екземпляр цього класу, будь ласка, тримайся його і повертай мені, коли я запитую".

  • @Autowiredкаже "будь ласка, дайте мені примірник цього класу, наприклад, той, який я створив із @Beanанотацією раніше".

Чи має це сенс? У вашому першому прикладі ви просите Spring дати вам екземпляр BookingService, але ви ніколи не створюєте його, тому Spring не має що вам дати. У вашому другому прикладі ви створюєте новий екземпляр BookingService, повідомляючи про це Spring, а потім у main()методі просите його повернути.

Якщо ви хочете, ви можете видалити два додаткові рядки з другого main()методу та об’єднати два приклади, як показано нижче:

@SpringBootApplication
public class Application {

  @Autowired
  BookingService bookingService;

  @Bean
  BookingService bookingService() {
    return new BookingService();
  }

  public static void main(String[] args) {
    bookingService.book("Alice", "Bob", "Carol");
  }
}

У цьому випадку @Beanанотація дає Spring BookingService, і цим @Autowiredкористується.

Це був би трохи безглуздий приклад, оскільки ви використовуєте все це в одному класі, але це стає корисним, якщо у вас є @Beanвизначені в одному класі, а @Autowiredв іншому.


1
Якось така відповідь здається мені лише частково правильною. Автоматичне підключення також може викликати об'єкти, позначені @Components. Більше того, Autowired можна використовувати для Методів не тільки для об'єктів.
— PowerFlower

7
@PowerFlower, абсолютно правильно, я мав тут на меті пояснити різницю в контексті запитання. Звичайно, в обох анотаціях є набагато більше складності, але я намагався дати просте пояснення на високому рівні для цього конкретного прикладу.
— DaveyDaveDave

12
@Bean
BookingService bookingService() {
    return new BookingService();
}

Анотація @Beanреєструє службу лише як компонент (тип Об’єкта) у контексті весняної програми. Простими словами, це просто реєстрація і нічого іншого.

@Autowired
BookingService bookingService;

Анотування змінної за допомогою @Autowiredін’єкції BookingServiceкомпонента (тобто об’єкта) із контексту Spring Application.

(тобто) Зареєстрований компонент із @Beanанотацією буде введено у змінну, котру коментують @Autowired.

Сподіваюся, це змусить ваші сумніви!


але я не можу використовувати функцію BookingService, якщо ввожу BookingService з @Autowired
— zhuochen shen

Тепер я знаю, що це тому, що в main () я отримав помилку "змінити модифікатор book () на статичний", я можу використовувати об'єкт BookingService в інших функціях. Але я не знаю чому
— zhuochen shen

@zhuochenshen Я не впевнений, що є у вас у класі та поточна проблема. Я відповів лише на ваше запитання "різниці". Ви можете опублікувати ще одне запитання щодо вашої наступної проблеми.
— pmverma

1
I.E,registered bean with @Bean will be inject to the variable annotated with @Autowired.Цей рядок виявляється суттю всього, що стосується цих двох анотацій.
— Мікайїл Абдуллаєв

5

чудова відповідь від @DaveyDaveDave У прикладі замість

@Bean
  BookingService bookingService() {
    return new BookingService();
  }

Ви можете використовувати анотацію @Service в класі BookingService


2

Ось хороша стаття про анотацію @Autowired: http://www.baeldung.com/spring-autowire

Анотація @Autowired може створити інстанції для ін'єкцій, визначивши @ComponentScan ("namespace.with.your.components.for.inject") у класі конфігурації

@Configuration
@ComponentScan("com.baeldung.autowire.sample")
public class AppConfig {}

Усі компоненти повинні бути позначені анотацією @Component. Він замінює анотацію @Bean.


0

@Bean - це лише для визначення метаданих для створення компонента (еквівалентно тегу). @Autowired полягає у введенні залежності в компонент (еквівалент ref XML тегу / атрибуту).


0

Незалежно від того, який клас ви створили за допомогою @Autowire, ви можете створити його всередині класу за допомогою анотації @Configuration, використовуючи @Bean у методі.

Як @Autowire, так і @Bean - це способи ініціалізації екземплярів класу.

Різниця полягає в тому, що якщо ви використовуєте @Bean для створення екземпляра класу, ви більше контролюєте ініціалізацію. Наприклад, якщо ви створюєте екземпляр класу вимикача Resilience4J, якщо ви робите це всередині методу за допомогою @Bean, у вас є можливість встановити всю конфігурацію за допомогою коду, подібного цьому

@Bean
public CircuitBreaker fooCircuitBreaker() {
    CircuitBreakerConfig.Builder builder = CircuitBreakerConfig.custom().
            slidingWindowSize(xxx).
            failureRateThreshold(xxx).
            waitDurationInOpenState(xxx)).
            ignoreException(e -> {
                if (e instanceof HttpStatusCodeException) {
                    HttpStatusCodeException httpStatusCodeException = (HttpStatusCodeException) e;
                    if (httpStatusCodeException.getStatusCode().is4xxClientError()) {
                        return true;
                    }
                }
                return false;
            });
    circuitBreakerRegistry.addConfiguration(xxx, builder.build());
    return circuitBreakerRegistry.circuitBreaker(xxx, xxx);
}

У такому випадку використання @Bean, очевидно, є кращим способом.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.