@Resource vs @Autowired

380

Welche Annotation, @Resource ( jsr250 ) oder @Autowired (Spring-spezifisch), sollte ich in DI verwenden?

Ich habe erfolgreich eingesetzt , sowohl in der Vergangenheit, @Resource(name="blah")und@Autowired @Qualifier("blah")

Mein Instinkt ist es, bei dem @ResourceTag zu bleiben, da es von den jsr-Leuten ratifiziert wurde.
Hat jemand starke Gedanken dazu?

mlo55
quelle
Zu Ihrer Information - Ich habe das 'Update' entfernt, es hätte als separate Frage gestellt werden sollen. Gemäß diesem abgelehnten Kommentar "weicht diese Änderung von der ursprünglichen Absicht des Beitrags ab. Selbst Änderungen, die drastische Änderungen vornehmen müssen, sollten sich bemühen, die Ziele des Eigentümers des Beitrags zu bewahren"
mlo55

Antworten:

194

Im Frühjahr vor 3.0 spielt es keine Rolle, welches.

In Frühjahr 3.0 wird die Standardanmerkung ( JSR-330 ) unterstützt @javax.inject.Inject- verwenden Sie sie mit einer Kombination aus @Qualifier. Beachten Sie, dass spring jetzt auch die @javax.inject.QualifierMeta-Annotation unterstützt:

@Qualifier
@Retention(RUNTIME)
public @interface YourQualifier {}

So können Sie haben

<bean class="com.pkg.SomeBean">
   <qualifier type="YourQualifier"/>
</bean>

oder

@YourQualifier
@Component
public class SomeBean implements Foo { .. }

Und dann:

@Inject @YourQualifier private Foo foo;

Dies macht weniger Gebrauch von String-Namen, die falsch geschrieben werden können und schwieriger zu pflegen sind.


Was die ursprüngliche Frage betrifft: Beide führen ohne Angabe von Attributen der Annotation eine Injektion nach Typ durch. Der Unterschied ist:

  • @Resource Mit dieser Option können Sie einen Namen für die injizierte Bean angeben
  • @Autowired ermöglicht es Ihnen, es als nicht obligatorisch zu markieren.
Bozho
quelle
Dies mag wie eine dumme Frage erscheinen, aber wenn Sie diese Art der Injektion verwenden, benötigen Sie einen öffentlichen Setter für foooder einen Konstruktor SomeBeanmit einem FooParameter?
Snekse
@Snekse - Bekam meine Antwort: stackoverflow.com/questions/3536674/…
Snekse
Nee. Sie brauchen nichts davon. Nur das Feld. (Frühling bevölkert es durch Reflexion)
Bozho
@Bozho Diese Antwort zeigt tatsächlich nicht den Unterschied zwischen @Resourceund @Autowired, die tatsächliche Antwort ist die von @Ichthyo gepostete. Ich denke, diese muss aktualisiert werden.
Boris Treukhov
1
Ja. Tatsächlich beantworte ich manchmal Fragen, indem ich eine bessere Alternative zum Ansatz anbiete. Aber ich habe die Antwort auf die ursprüngliche Frage unten der Vollständigkeit
halber aufgenommen
509

Beide @Autowired(oder @Inject) und @Resourcefunktionieren gleich gut. Aber es gibt einen konzeptuellen Unterschied oder einen Unterschied in der Bedeutung

  • @Resourcebedeutet, mir eine bekannte Ressource mit Namen zu besorgen . Der Name wird aus dem Namen des mit Anmerkungen versehenen Setzers oder Felds extrahiert oder aus dem Namen-Parameter übernommen.
  • @Injectoder @Autowiredversuchen Sie, eine geeignete andere Komponente nach Typ zu verdrahten .

Im Grunde sind dies also zwei ziemlich unterschiedliche Konzepte. Leider verfügt die Spring-Implementierung von @Resourceüber einen integrierten Fallback, der aktiviert wird, wenn die Auflösung nach Namen fehlschlägt. In diesem Fall wird auf die @AutowiredArtauflösung nach Art zurückgegriffen. Obwohl dieser Fallback praktisch ist, verursacht er @Resourcemeiner Meinung nach viel Verwirrung, da die Leute sich des konzeptionellen Unterschieds nicht bewusst sind und ihn eher für typbasiertes Autowiring verwenden.

Ichthyo
quelle
81
Ja, dies sollte eine akzeptierte Antwort sein. Wenn Sie beispielsweise ein mit @ResourceAnmerkungen versehenes Feld haben und der Feldname mit der ID einer Bean im Container org.springframework.beans.factory.BeanNotOfRequiredTypeExceptionübereinstimmt, wird Spring ausgelöst, wenn sich ihre Typen unterscheiden. Dies liegt daran, dass Beans zuerst nach Namen in @ResourceAnmerkungen und nicht nach Typ abgeglichen werden . Wenn der Name der Eigenschaft jedoch nicht mit dem Namen der Bean übereinstimmt, werden sie von Spring nach Typ verkabelt.
Boris Treukhov
Sie können auf den anderen Beitrag verweisen, der den Unterschied zwischen diesen beiden aufzeigt, wenn Sie versuchen, eine einfache MAP zu verwenden. stackoverflow.com/questions/13913752/…
Anver Sadhat
4
+1 für die tatsächliche Beantwortung der Frage, anstatt einfach eine ganz andere "Best Practice" zu empfehlen als die akzeptierte Antwort. Ich fand auch diesen Blog-Beitrag, der Ergebnisse mehrerer gängiger Szenarien mit allen drei Anmerkungsstilen zeigt, hilfreich: blogs.sourceallies.com/2011/08/…
Jules
1
Für den Leser finden Sie eine Zusammenfassung des Artikels von @Jules hier: stackoverflow.com/a/23887596/363573
Stephan
3
Eine Implikation davon: Wenn Sie eine Map / List-Bean injizieren möchten, @Autowirekann und wird dies nicht funktionieren. Sie müssen @Resourcein diesem Fall verwenden.
Ricardo van den Broek
76

Der Hauptunterschied besteht darin, dass @Autowiredes sich um eine Federanmerkung handelt. Während @Resourcewird vom JSR-250 spezifiziert, wie Sie selbst betont haben. Letzteres ist also Teil von Java, während Ersteres Frühlingsspezifisch ist.

Sie haben also Recht, wenn Sie dies in gewissem Sinne vorschlagen. Ich fand Leute verwenden @Autowiredmit, @Qualifierweil es mächtiger ist. Der Übergang von einem Rahmen zu einem anderen wird als sehr unwahrscheinlich, wenn nicht als Mythos angesehen, insbesondere im Fall des Frühlings.

Adeel Ansari
quelle
7
1, weil @Autowiredmit @Qualifierwirklich ist mächtiger als die JSR Standard @ResourceAnnotation (man denke an optionalen Abhängigkeiten zum Beispiel mit @Autowired(required=false). Sie können das nicht mit @Resource)
Stefan Haberl
70

Ich möchte einen Kommentar von @Jules zu dieser Antwort auf diese Frage hervorheben . Der Kommentar enthält einen nützlichen Link: Spring Injection mit @Resource, @Autowired und @Inject . Ich ermutige Sie, es vollständig zu lesen. Hier ist jedoch eine kurze Zusammenfassung seiner Nützlichkeit:

Wie wählen Anmerkungen die richtige Implementierung aus?

@Autowired und @Inject

  1. Übereinstimmungen nach Typ
  2. Einschränkungen durch Qualifikanten
  3. Übereinstimmungen nach Namen

@Resource

  1. Übereinstimmungen nach Namen
  2. Übereinstimmungen nach Typ
  3. Einschränkungen durch Qualifikanten (wird ignoriert, wenn die Übereinstimmung nach Namen gefunden wird)

Welche Anmerkungen (oder Kombinationen von) sollte ich zum Injizieren meiner Bohnen verwenden?

  1. Benennen Sie Ihre Komponente explizit [@Component ("beanName")]

  2. Verwendung @Resourcemit dem nameAttribut [@Resource (name = "beanName")]

Warum sollte ich nicht verwenden @Qualifier?

Vermeiden Sie @QualifierAnmerkungen, es sei denn, Sie möchten eine Liste ähnlicher Beans erstellen. Beispielsweise möchten Sie möglicherweise eine Reihe von Regeln mit einer bestimmten @QualifierAnmerkung markieren . Dieser Ansatz macht es einfach, eine Gruppe von Regelklassen in eine Liste einzufügen, die zur Datenverarbeitung verwendet werden kann.

Verlangsamt die Bohneninjektion mein Programm?

Scannen Sie bestimmte Pakete nach Komponenten [context:component-scan base-package="com.sourceallies.person"]. Dies führt zwar zu mehr component-scanKonfigurationen, verringert jedoch die Wahrscheinlichkeit, dass Sie Ihrem Spring-Kontext unnötige Komponenten hinzufügen.


Referenz: Spring Injection mit @Resource, @Autowired und @Inject

Stephan
quelle
39

Folgendes habe ich aus dem Spring 3.0.x-Referenzhandbuch erhalten : -

Trinkgeld

Wenn Sie eine annotationsgesteuerte Injektion nach Namen ausdrücken möchten, verwenden Sie @Autowired nicht primär, auch wenn Sie technisch in der Lage sind, über @Qualifier-Werte auf einen Bean-Namen zu verweisen. Verwenden Sie stattdessen die Annotation JSR-250 @Resource, die semantisch definiert ist, um eine bestimmte Zielkomponente anhand ihres eindeutigen Namens zu identifizieren, wobei der deklarierte Typ für den Abgleichsprozess irrelevant ist.

Als spezifische Konsequenz dieses semantischen Unterschieds können Beans, die selbst als Sammlung oder Kartentyp definiert sind, nicht über @Autowired injiziert werden, da die Typübereinstimmung für sie nicht ordnungsgemäß anwendbar ist. Verwenden Sie @Resource für solche Beans und verweisen Sie auf die bestimmte Sammlung oder Map-Bean mit einem eindeutigen Namen.

@Autowired gilt für Felder, Konstruktoren und Methoden mit mehreren Argumenten, sodass Qualifikationsanmerkungen auf Parameterebene eingegrenzt werden können. Im Gegensatz dazu wird @Resource nur für Felder und Bean-Eigenschaftssetzermethoden mit einem einzigen Argument unterstützt. Halten Sie sich daher an Qualifizierer, wenn Ihr Injektionsziel ein Konstruktor oder eine Methode mit mehreren Argumenten ist.

Kartik
quelle
Für die aktuelle Version siehe docs.spring.io/spring/docs/current/spring-framework-reference/… (der Tipp wurde aktualisiert)
Lu55
28

@Autowired + @Qualifier funktioniert nur mit Spring DI, wenn Sie in Zukunft einen anderen DI verwenden möchten. @Resource ist eine gute Option.

Ein weiterer Unterschied, den ich als sehr bedeutsam empfand, ist, dass @Qualifier keine dynamische Bean-Verkabelung unterstützt, da @Qualifier keine Platzhalter unterstützt, während @Resource dies sehr gut tut.

Zum Beispiel: Wenn Sie eine Schnittstelle mit mehreren Implementierungen wie dieser haben

interface parent {

}
@Service("actualService")
class ActualService implements parent{

}
@Service("stubbedService")
class SubbedService implements parent{

}

Mit @Autowired & @Qualifier müssen Sie eine bestimmte untergeordnete Implementierung wie festlegen

@Autowired
@Qualifier("actualService") or 
@Qualifier("stubbedService") 
Parent object;

Wenn Sie mit @Resource keinen Platzhalter bereitstellen, können Sie einen Platzhalter einfügen und eine Eigenschaftendatei verwenden, um eine bestimmte untergeordnete Implementierung wie zu injizieren

@Resource(name="${service.name}")
Parent object;  

Dabei wird service.name in der Eigenschaftendatei als festgelegt

#service.name=actualService
 service.name=stubbedService

Hoffe das hilft jemandem :)

Ali
quelle
16

Beide sind gleich gut. Der Vorteil der Verwendung von Resource besteht in Zukunft darin, dass Ihre Codeänderungen viel einfacher sind, wenn Sie ein anderes DI-Framework als Spring verwenden möchten. Bei Verwendung von Autowired ist Ihr Code eng mit den Federn DI verbunden.

Teja Kantamneni
quelle
17
Wird nie passieren. Und selbst wenn dies der Fall wäre - das Suchen / Ersetzen von Anmerkungsnamen ist das geringste Ihrer Probleme.
Daniel Alexiuc
13

Wenn Sie die Basisklassen dieser beiden Anmerkungen kritisch analysieren, werden Sie die folgenden Unterschiede feststellen.

@Autowiredwird verwendet AutowiredAnnotationBeanPostProcessor , um Abhängigkeiten einzufügen.
@Resourcewird verwendet CommonAnnotationBeanPostProcessor, um Abhängigkeiten einzufügen.

Obwohl sie unterschiedliche Postprozessorklassen verwenden, verhalten sich alle nahezu identisch. Die Unterschiede liegen kritisch in ihren Ausführungspfaden, die ich unten hervorgehoben habe.

@Autowired / @Inject

1. Übereinstimmungen nach Typ
2. Einschränkungen nach Qualifikationsmerkmalen
3. Übereinstimmungen nach Namen

@Resource

1. Übereinstimmungen nach Namen
2. Übereinstimmungen nach Typ
3. Einschränkungen nach Qualifikationsmerkmalen (werden ignoriert, wenn Übereinstimmungen nach Namen gefunden werden)

Amos Kosgei
quelle
6

Wenn @ResourceSie die Bean-Selbstinjektion durchführen können, ist dies möglicherweise erforderlich, um die gesamte zusätzliche Logik auszuführen, die von Bean-Postprozessoren wie Transaktions- oder sicherheitsrelevanten Dingen hinzugefügt wurde.

Mit Spring 4.3+ @Autowiredist dies auch möglich.

Bohdan Levchenko
quelle
2

@Resourcewird häufig von übergeordneten Objekten verwendet, die über JNDI definiert sind. @Autowiredoder @Injectwird von allgemeineren Bohnen verwendet.

Soweit ich weiß, handelt es sich weder um eine Spezifikation noch um eine Konvention. Es ist eher die logische Art und Weise, wie Standardcode diese Anmerkungen verwendet.

Nicolas Zozol
quelle
0

Als Hinweis hier: SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContextund SpringBeanAutowiringSupport.processInjectionBasedOnServletContext funktioniert NICHT mit @Resource Anmerkungen. Es gibt also Unterschiede.

msangel
quelle