Різниця між @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.