Comprendre L'utilisation de Spring @Autowired

Je lis le printemps 3.0.x documentation de référence pour comprendre l'annotation Spring Autowired:

3.9.2 @Autocâblés et @Inject

Je ne suis pas capable de comprendre les exemples ci-dessous. Avons-nous besoin de faire quelque chose dans le XML pour que cela fonctionne?

Exemple 1

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}

Exemple 2

public class MovieRecommender {

    private MovieCatalog movieCatalog;

    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public void prepare(MovieCatalog movieCatalog,
                    CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

Comment les deux classes peuvent-elles être autowired implémentant la même interface et utilisant la même classe?

Exemple:

class Red implements Color
class Blue implements Color

class myMainClass{
    @Autowired 
    private Color color;

    draw(){
        color.design(); 
    } 
}

Quelle méthode de conception être appelé? Comment puis-je m'assurer que la méthode de conception de la classe rouge sera appelée et non bleue?

243
demandé sur Pragati Singh 2013-10-17 02:02:46

4 réponses

TL;DR

L'annotation @ Autowired vous épargne le besoin de faire le câblage par vous-même dans le fichier XML (ou de toute autre manière) et trouve juste pour vous ce qui doit être injecté où, et le fait pour vous.

Explication Complète

L'annotation @Autowired vous permet de sauter des configurations ailleurs de ce qu'il faut injecter et le fait juste pour vous. En supposant que votre paquet est com.mycompany.movies, Vous devez mettre cette balise dans votre XML (contexte d'application fichier):

<context:component-scan base-package="com.mycompany.movies" />

Cette balise fera un balayage automatique. En supposant que chaque classe qui doit devenir un bean est annotée avec une annotation correcte comme @Component (pour un bean simple) ou @Controller (pour un contrôle de servlet) ou @Repository (pour les classes DAO) et que ces classes sont quelque part sous le paquet com.mycompany.movies, Spring trouvera tout cela et créera un bean pour chacune. Ceci est fait dans 2 scans des classes-la première fois qu'il recherche simplement les classes qui doivent devenir un haricot et mappe les injections doit être fait, et sur la deuxième analyse, il injecte les haricots. Bien sûr, vous pouvez définir vos beans dans le fichier XML plus traditionnel ou avec une classe @Configuration (ou n'importe quelle combinaison des trois).

L'annotation @Autowired indique à Spring où une injection doit avoir lieu. Si vous le mettez sur une méthode setMovieFinder, il comprend (par le préfixe set + le @Autowired annotation) qu'un bean doit être injectée. Dans la deuxième analyse, Spring recherche un bean de type MovieFinder, et s'il trouve un tel haricot, il l'injecte à cette méthode. S'il trouve deux de ces haricots, vous obtiendrez un Exception. Pour éviter le Exception, Vous pouvez utiliser l'annotation @Qualifier et lui dire lequel des deux haricots à injecter de la manière suivante:

@Qualifier("redBean")
class Red implements Color {
   // Class code here
}

@Qualifier("blueBean")
class Blue implements Color {
   // Class code here
}

Ou si vous préférez déclarer les beans dans votre XML, cela ressemblerait à ceci:

<bean id="redBean" class="com.mycompany.movies.Red"/>

<bean id="blueBean" class="com.mycompany.movies.Blue"/>

Dans la déclaration @Autowired, vous devez également ajouter le @Qualifier pour indiquer lequel des deux haricots de couleur à injecter:

@Autowired
@Qualifier("redBean")
public void setColor(Color color) {
  this.color = color;
}

Si vous ne voulez pas l'utilisation de deux annotations (la @Autowired et @Qualifier) vous pouvez utiliser @Resource pour combiner ces deux:

@Resource(name="redBean")
public void setColor(Color color) {
  this.color = color;
}

Le @Resource (vous pouvez lire quelques données supplémentaires à ce sujet dans le premier commentaire sur cette réponse) vous épargne l'utilisation de deux annotations et au lieu d'une seule.

Je vais juste ajouter deux autres commentaires:

  1. Bonne pratique serait d'utiliser @Inject au lieu de @Autowired, car il n'est pas le Printemps et une partie de la JSR-330 standard.
  2. une autre bonne pratique serait de mettre le @Inject / @Autowired sur un constructeur au lieu d'une méthode. Si vous le mettez sur un constructeur, vous pouvez valider que les beans injectés ne sont pas nuls et échouent rapidement lorsque vous essayez de démarrer l'application et évitez un NullPointerException lorsque vous devez réellement utiliser le bean.

Update : pour compléter l'image, j'ai créé une nouvelle question sur la classe @Configuration.

469
répondu Avi 2018-10-01 06:46:45

Rien dans l'exemple ne dit que les "classes implémentant la même interface". MovieCatalog est un type et CustomerPreferenceDao est un autre type. Le printemps peut facilement les distinguer.

Au Printemps 2.x, le câblage des haricots s'est principalement produit via des identifiants ou des noms de haricots. Ceci est toujours pris en charge par Spring 3.x mais souvent, vous aurez une instance d'un bean avec un certain type - la plupart des services sont des singletons. Créer des noms pour ceux-ci est fastidieux. Le printemps a donc commencé à prendre en charge "autowire par type".

Quels sont les exemples show est une variété de façons que vous pouvez utiliser pour injecter des beans dans les champs, les méthodes et les constructeurs.

Le XML contient déjà toutes les informations dont Spring a besoin puisque vous devez spécifier le nom de classe complet dans chaque bean. Vous devez être un peu prudent avec les interfaces, cependant:

Cet autowiring échouera:

 @Autowired
 public void prepare( Interface1 bean1, Interface1 bean2 ) { ... }

Puisque Java ne conserve pas les noms de paramètres dans le code d'octet, Spring ne peut plus distinguer les deux beans. La solution est d'utiliser @Qualifier:

 @Autowired
 public void prepare( @Qualifier("bean1") Interface1 bean1,
     @Qualifier("bean2")  Interface1 bean2 ) { ... }
16
répondu Aaron Digulla 2016-01-28 10:52:51

Oui, vous pouvez configurer le fichier xml de contexte de servlet Spring pour définir vos beans (c'est-à-dire les classes), afin qu'il puisse effectuer l'injection automatique pour vous. Cependant, notez que vous devez faire d'autres configurations pour que Spring soit opérationnel et que la meilleure façon de le faire est de suivre un tutoriel.

Une fois que vous avez probablement configuré votre Spring, vous pouvez faire ce qui suit dans votre fichier xml de contexte de servlet Spring par exemple 1 ci-dessus pour fonctionner (veuillez Remplacer le paquet nom de com.movies à quel est le vrai nom du paquet et s'il s'agit d'une classe tierce, alors assurez-vous que le fichier JAR approprié est sur le classpath):

<beans:bean id="movieFinder" class="com.movies.MovieFinder" />

Ou si la classe MovieFinder a un constructeur avec une valeur primitive, alors vous pourriez quelque chose comme ceci,

<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
    <beans:constructor-arg value="100" />
</beans:bean>

Ou si la classe MovieFinder a un constructeur qui attend une autre classe, alors vous pouvez faire quelque chose comme ceci,

<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
    <beans:constructor-arg ref="otherBeanRef" />
</beans:bean>

...où ' otherBeanRef ' est un autre haricot qui a un référence à la classe attendue.

5
répondu Cem Sultan 2013-10-17 00:29:00

@Autocâblés

Laissez Spring auto-câbler d'autres beans dans vos classes en utilisant l'annotation @ Autowired.

@Service
public class CompanyServiceImpl implements CompanyService {

    @Autowired
    private CompanyDAO companyDAO;

    ...
}

Pointe D'Annotation de printemps les haricots de printemps peuvent être câblés par nom ou par type. @Autowire par défaut est une injection pilotée par type. @ Qualifier Spring annotation peut être utilisé pour affiner davantage autowiring. @Resource (javax.annotation.Ressource) annotation peut être utilisé pour le câblage par nom. Les haricots qui sont 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 se référant à la collection spécifique ou à la carte bean par nom unique

5
répondu aman 2015-08-28 23:31:28