@Resource vs @Autowired

381

Quelle annotation, @Resource ( jsr250 ) ou @Autowired (spécifique à Spring) dois-je utiliser dans DI?

J'ai utilisé avec succès à la fois dans le passé @Resource(name="blah")et@Autowired @Qualifier("blah")

Mon instinct est de rester avec le @Resourcetag car il a été ratifié par le peuple jsr.
Quelqu'un a des pensées fortes à ce sujet?

mlo55
la source
Pour info - j'ai supprimé la «mise à jour», elle aurait dû être posée comme une question distincte. Selon ce commentaire rejeté, "Cette modification s'écarte de l'intention initiale du message. Même les modifications qui doivent apporter des changements radicaux devraient s'efforcer de préserver les objectifs du propriétaire du message"
mlo55

Réponses:

195

Au printemps pré-3.0, peu importe lequel.

Au printemps 3.0, l' annotation standard ( JSR-330 ) est prise en charge @javax.inject.Inject- utilisez-la avec une combinaison de @Qualifier. Notez que Spring prend désormais également en charge la @javax.inject.Qualifierméta-annotation:

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

Vous pouvez donc avoir

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

ou

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

Et alors:

@Inject @YourQualifier private Foo foo;

Cela utilise moins les noms de chaîne, qui peuvent être mal orthographiés et sont plus difficiles à maintenir.


Quant à la question d'origine: les deux, sans spécifier d'attributs de l'annotation, effectuent l'injection par type. La différence est:

  • @Resource vous permet de spécifier le nom du bean injecté
  • @Autowired vous permet de le marquer comme non obligatoire.
Bozho
la source
Cela peut sembler une question stupide, mais lorsque vous utilisez ce style d'injection, avez-vous besoin d'un setter public fooou d'un constructeur SomeBeanavec un Fooparamètre?
Snekse
@Snekse - J'ai ma réponse: stackoverflow.com/questions/3536674/…
Snekse
Nan. Vous n'avez besoin de rien de tout cela. Juste le terrain. (Le printemps le remplit par réflexion)
Bozho
@Bozho Cette réponse ne montre pas la différence entre @Resourceet @Autowired, la réponse réelle est celle publiée par @Ichthyo, je pense que celle-ci doit être mise à jour.
Boris Treukhov
1
Oui. En fait, je réponds parfois aux questions en offrant une meilleure alternative à l'approche. Mais j'ai inclus la réponse à la question d'origine ci-dessous, pour être complet
Bozho
509

Les deux @Autowired(ou @Inject) et @Resourcefonctionnent aussi bien. Mais il y a une différence conceptuelle ou une différence de sens

  • @Resourcesignifie me procurer une ressource connue par son nom . Le nom est extrait du nom du setter ou du champ annoté, ou il est extrait du paramètre name.
  • @Injectou @Autowiredessayez de câbler un autre composant approprié par type .

Donc, fondamentalement, ce sont deux concepts bien distincts. Malheureusement, Spring-Implementation @Resourcea un repli intégré, qui se déclenche lorsque la résolution par nom échoue. Dans ce cas, il revient au @Autowiredtype de résolution -kind. Bien que cette solution de repli soit pratique, à @Resourcemon humble avis , elle provoque beaucoup de confusion, car les gens ne connaissent pas la différence conceptuelle et ont tendance à utiliser pour le câblage automatique basé sur le type.

Ichthyo
la source
81
Oui, c'est ce qui devrait être une réponse acceptée. Par exemple, si vous avez un @Resourcechamp annoté et que le nom du champ correspond à l'ID d'un bean dans le conteneur, Spring lancera org.springframework.beans.factory.BeanNotOfRequiredTypeExceptionsi leurs types diffèrent - c'est parce que les beans sont d'abord mis en correspondance par nom dans l' @Resourceannotation, pas par type. Mais si le nom de la propriété ne correspond pas au nom du bean, Spring les câblera par type.
Boris Treukhov
Vous pouvez vous référer à l'autre article qui fait la différence entre ces deux lorsque vous essayez d'utiliser une simple carte. stackoverflow.com/questions/13913752/…
Anver Sadhat
4
+1 pour avoir réellement répondu à la question plutôt que de simplement recommander une «meilleure pratique» entièrement différente comme le fait la réponse acceptée. J'ai également trouvé cet article de blog, qui montre les résultats de plusieurs scénarios courants avec les trois styles d'annotation, utile: blogs.sourceallies.com/2011/08/…
Jules
1
Pour le lecteur, veuillez trouver un résumé de l'article signalé par @Jules ici: stackoverflow.com/a/23887596/363573
Stephan
3
Une implication de ceci: lorsque vous voulez injecter un bean Map / List, @Autowirecela ne peut pas et ne fonctionnera pas. Vous devrez utiliser @Resourcedans ce cas.
Ricardo van den Broek
76

La principale différence @Autowiredest une annotation de ressort. Alors que @Resourcele JSR-250 le spécifie, comme vous l'avez souligné vous-même. Donc, ce dernier fait partie de Java alors que le premier est spécifique à Spring.

Par conséquent, vous avez raison de suggérer cela, dans un sens. J'ai trouvé des gens utilisent @Autowiredavec , @Qualifiercar il est plus puissant. Passer d'un cadre à un autre est considéré comme très improbable, sinon mythique, en particulier dans le cas du printemps.

Adeel Ansari
la source
7
+1, car @Autowiredavec est@Qualifier vraiment plus puissant que l' annotation standard JSR (pensez aux dépendances optionnelles par exemple avec . Vous ne pouvez pas le faire avec )@Resource@Autowired(required=false)@Resource
Stefan Haberl
70

Je voudrais souligner un commentaire de @Jules sur cette réponse à cette question. Le commentaire apporte un lien utile: Spring Injection avec @Resource, @Autowired et @Inject . Je vous encourage à le lire entièrement, cependant voici un bref résumé de son utilité:

Comment les annotations sélectionnent la bonne implémentation?

@Autowired et @Inject

  1. Correspondances par type
  2. Restrictions par qualificatifs
  3. Matchs par nom

@Resource

  1. Matchs par nom
  2. Correspondances par type
  3. Limites par qualificatifs (ignorées si une correspondance est trouvée par nom)

Quelles annotations (ou combinaison de) dois-je utiliser pour injecter mes grains?

  1. Nommez explicitement votre composant [@Component ("beanName")]

  2. Utiliser @Resourceavec l' nameattribut [@Resource (name = "beanName")]

Pourquoi ne devrais-je pas utiliser @Qualifier?

Évitez les @Qualifierannotations sauf si vous souhaitez créer une liste de beans similaires. Par exemple, vous souhaiterez peut-être marquer un ensemble de règles avec une @Qualifierannotation spécifique . Cette approche simplifie l'injection d'un groupe de classes de règles dans une liste qui peut être utilisée pour le traitement des données.

L'injection de haricots ralentit-elle mon programme?

Analyser des packages spécifiques pour les composants [context:component-scan base-package="com.sourceallies.person"]. Bien que cela se traduise par plus de component-scanconfigurations, cela réduit les chances que vous ajoutiez des composants inutiles à votre contexte Spring.


Référence: Spring Injection avec @Resource, @Autowired et @Inject

Stephan
la source
39

Voici ce que j'ai obtenu du manuel de référence Spring 3.0.x : -

Pointe

Si vous avez l'intention d'exprimer l'injection basée sur des annotations par nom, n'utilisez pas principalement @Autowired, même s'il est techniquement capable de faire référence à un nom de bean via les valeurs @Qualifier. À la place, utilisez l'annotation JSR-250 @Resource, qui est définie sémantiquement pour identifier un composant cible spécifique par son nom unique, le type déclaré n'étant pas pertinent pour le processus de correspondance.

Conséquence spécifique de cette différence sémantique, les beans eux-mêmes définis comme un type de collection ou de carte ne peuvent pas être injectés via @Autowired, car la correspondance de type ne leur est pas correctement applicable. Utilisez @Resource pour ces beans, en vous référant à la collection spécifique ou au bean de carte par nom unique.

@Autowired s'applique aux champs, aux constructeurs et aux méthodes multi-arguments, ce qui permet de restreindre les annotations de qualificateur au niveau des paramètres. En revanche, @Resource n'est pris en charge que pour les champs et les méthodes de définition de propriétés de bean avec un seul argument. Par conséquent, respectez les qualificatifs si votre cible d'injection est un constructeur ou une méthode multi-arguments.

Kartik
la source
Pour la version actuelle, voir docs.spring.io/spring/docs/current/spring-framework-reference/… (le conseil a été mis à jour)
Lu55
28

@Autowired + @Qualifier ne fonctionnera qu'avec la DI de ressort, si vous souhaitez utiliser une autre DI à l'avenir @Resource est une bonne option.

une autre différence que j'ai trouvée très significative est que @Qualifier ne prend pas en charge le câblage de bean dynamique, car @Qualifier ne prend pas en charge l'espace réservé, tandis que @Resource le fait très bien.

Par exemple: si vous avez une interface avec plusieurs implémentations comme celle-ci

interface parent {

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

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

}

avec @Autowired et @Qualifier, vous devez définir une implémentation enfant spécifique comme

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

qui ne fournit pas d'espace réservé tandis qu'avec @Resource vous pouvez mettre un espace réservé et utiliser un fichier de propriétés pour injecter une implémentation enfant spécifique comme

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

où service.name est défini dans le fichier de propriétés comme

#service.name=actualService
 service.name=stubbedService

J'espère que cela aide quelqu'un :)

Ali
la source
16

Les deux sont tout aussi bons. L'avantage d'utiliser Resource est à l'avenir si vous voulez un autre framework DI autre que Spring, vos changements de code seront beaucoup plus simples. En utilisant Autowired votre code est étroitement couplé avec des ressorts DI.

Teja Kantamneni
la source
17
Cela n'arrivera jamais. Et même si c'est le cas - faire une recherche / remplacement sur les noms d'annotation sera le moindre de vos problèmes.
Daniel Alexiuc
13

Lorsque vous effectuez une analyse critique à partir des classes de base de ces deux annotations, vous réalisez les différences suivantes.

@Autowiredutilise AutowiredAnnotationBeanPostProcessor pour injecter des dépendances.
@Resourceutilise CommonAnnotationBeanPostProcessorpour injecter des dépendances.

Même s'ils utilisent différentes classes de post-processeur, ils se comportent tous de façon presque identique. Les différences résident essentiellement dans leurs voies d'exécution, que j'ai soulignées ci-dessous.

@Autowired / @Inject

1. correspondances par type
2. restrictions par qualificatifs
3. correspondances par nom

@Resource

1. correspondances par nom
2. correspondances par type
3. restrictions par qualificatifs (ignoré si une correspondance est trouvée par nom)

Amos Kosgei
la source
6

Avec @Resourcevous pouvez faire l'auto-injection de bean, cela peut être nécessaire pour exécuter toute la logique supplémentaire ajoutée par les post-processeurs de bean comme les transactions ou les choses liées à la sécurité.

Avec Spring 4.3+ @Autowiredest également capable de le faire.

Bohdan Levchenko
la source
2

@Resourceest souvent utilisé par des objets de haut niveau, définis via JNDI. @Autowiredou @Injectsera utilisé par des haricots plus courants.

Pour autant que je sache, ce n'est pas une spécification, ni même une convention. C'est plus la façon logique dont le code standard utilisera ces annotations.

Nicolas Zozol
la source
0

Comme une note ici: SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContextet SpringBeanAutowiringSupport.processInjectionBasedOnServletContext NE FONCTIONNE PAS avec l' @Resource annotation. Donc, il y a une différence.

msangel
la source