Unterschied zwischen @Bean und @Autowired

77

Warum kann ich @Autowiredin diesem Fall nicht verwenden ?

@SpringBootApplication
public class Application {

    @Autowired
    BookingService bookingService;

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

kann aber verwenden @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");
    }
}

Sind nicht die beiden Möglichkeiten, BookingServicedasselbe zu generieren ?

zhuochen shen
quelle
11
Bean Annotation dient zum Registrieren Ihrer Bean im Spring-Kontext, während Autowried Annotation dazu dient, die Bean aus dem Inhalt der Spring-Anwendung abzurufen und sie als Abhängigkeit für ein anderes Objekt zu
verdrahten
Sie sollten auch die BookingService-Klasse bereitstellen. Denn wenn das mit Component kommentiert ist, würde Ihre erste Klasse auch wie die zweite funktionieren.
PowerFlower

Antworten:

172

@Beanund @Autowiredmache zwei sehr unterschiedliche Dinge. Die anderen Antworten hier erklären etwas ausführlicher, aber auf einer einfacheren Ebene:

  • @Bean sagt Spring 'hier ist eine Instanz dieser Klasse, bitte halte sie fest und gib sie mir zurück, wenn ich frage'.

  • @Autowiredsagt 'Bitte geben Sie mir eine Instanz dieser Klasse, zum Beispiel eine, die ich @Beanzuvor mit einer Anmerkung erstellt habe'.

Ist das sinnvoll? In Ihrem ersten Beispiel bitten Sie Spring, Ihnen eine Instanz von zu geben BookingService, aber Sie erstellen nie eine, sodass Spring Ihnen nichts zu geben hat. In Ihrem zweiten Beispiel erstellen Sie eine neue Instanz von BookingService, erzählen Spring davon und main()fordern dann in der Methode diese zurück.

Wenn Sie möchten, können Sie die beiden zusätzlichen Zeilen aus der zweiten main()Methode entfernen und Ihre beiden Beispiele wie folgt kombinieren:

@SpringBootApplication
public class Application {

  @Autowired
  BookingService bookingService;

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

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

In diesem Fall gibt die @BeanAnnotation Spring das BookingServiceund @Autowirednutzt es.

Dies wäre ein etwas sinnloses Beispiel, da Sie alles in derselben Klasse verwenden. Es ist jedoch nützlich, wenn Sie das @Beanin einer Klasse und das @Autowiredin einer anderen Klasse definiert haben .

DaveyDaveDave
quelle
1
Irgendwie erscheint mir diese Antwort nur teilweise richtig. Autowired kann auch mit @Components kommentierte Objekte aufrufen. Darüber hinaus kann Autowired für Methoden nicht nur für Objekte verwendet werden.
PowerFlower
7
@ PowerFlower, absolut richtig, mein Punkt hier war es, den Unterschied im Kontext der Frage zu erklären. Sicherlich sind beide Anmerkungen viel komplexer, aber ich habe versucht, eine einfache Erklärung auf hoher Ebene für dieses spezielle Beispiel zu geben.
DaveyDaveDave
12
@Bean
BookingService bookingService() {
    return new BookingService();
}

Durch Annotieren wird @Beander Dienst nur als Bean (Art eines Objekts) im Kontext der Frühlingsanwendung registriert. In einfachen Worten, es ist nur Registrierung und sonst nichts.

@Autowired
BookingService bookingService;

Das Annotieren einer Variablen mit @Autowiredinjiziert eine BookingServiceBean (dh ein Objekt) aus dem Spring-Anwendungskontext.

(dh) Die registrierte Bean mit @BeanAnnotation wird in die mit Annotation versehene Variable eingefügt @Autowired.

Hoffe das klärt deinen Zweifel!

pmverma
quelle
Aber ich kann die Funktion von BookingService nicht verwenden, wenn ich BookingService mit @Autowired
zhuochen shen
Jetzt weiß ich, dass es daran liegt, dass ich in main () den Fehler "Modifikator von book () in static ändern" habe und das Objekt von BookingService in anderen Funktionen verwenden kann. Aber ich weiß nicht warum
zhuochen shen
@zhuochenshen Ich bin nicht sicher, was in dir Klasse und aktuelles Problem ist. Ich habe nur Ihre "Unterschied" -Frage beantwortet. Sie können eine weitere Frage zu Ihrem nächsten Problem stellen.
pmverma
1
I.E,registered bean with @Bean will be inject to the variable annotated with @Autowired.Diese Zeile erweist sich als die Essenz all dessen, worum es in diesen beiden Anmerkungen geht.
Mikayil Abdullayev
5

tolle Antwort von @DaveyDaveDave Im Beispiel statt

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

Sie können die @ Service-Annotation für die BookingService-Klasse verwenden

Kris Swat
quelle
2

Hier ist ein guter Artikel über @Autowired Annotation: http://www.baeldung.com/spring-autowire

Die Annotation @Autowired kann Ihre injizierbaren Dateien instanziieren, indem Sie @ComponentScan ("Namespace.with.your.components.for.inject") für die Konfigurationsklasse definieren

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

Alle Komponenten müssen mit der Annotation @Component gekennzeichnet sein. Es ersetzt die @ Bean-Annotation.

n0rtan
quelle
0

@Bean dient nur zur Erstellung der Bean durch die Metadatendefinition (entspricht Tag). @Autowired dient zum Injizieren der Abhängigkeit in eine Bean (entspricht dem XML-Tag / Attribut ref).

SARIKA
quelle
0

Unabhängig davon, welche Klasse Sie mit @Autowire instanziiert haben, können Sie sie innerhalb einer Klasse mit der Annotation @Configuration mithilfe von @Bean für die Methode instanziieren.

Sowohl @Autowire als auch @Bean sind Möglichkeiten, Instanzen einer Klasse zu initialisieren.

Der Unterschied besteht darin, dass Sie mehr Kontrolle über die Initialisierung haben, wenn Sie @Bean zum Instanziieren einer Klasse verwenden. Wenn Sie beispielsweise eine Resilience4J-Leistungsschalterklasse instanziieren und dies innerhalb einer Methode mit @Bean tun, haben Sie die Möglichkeit, die gesamte Konfiguration mithilfe des folgenden Codes festzulegen

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

In einem solchen Fall ist die Verwendung von @Bean offensichtlich der bessere Weg.

Entwickler747
quelle