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 en mesure 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?

Author: Pragati Singh, 2013-10-17

4 answers

TL;DR

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

Explication Complète

L'annotation @Autowired vous permet d'ignorer les configurations ailleurs de ce qu'il faut injecter et de le faire pour vous. En supposant que votre package 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 une analyse 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 DAO classes) et ces classes sont quelque part sous le paquet com.mycompany.movies, Spring trouvera tous ces éléments et créera un bean pour chacun. Cela se fait en 2 scans des classes - la première fois qu'il recherche simplement des classes qui doivent devenir un bean 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 beans 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 dire 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. Une bonne pratique serait d'utiliser @Inject au lieu de @Autowiredcar il n'est pas spécifique au ressort et fait partie de la norme JSR-330 .
  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 éviter 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
Author: 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. Spring a donc commencé à prendre en charge "autowire by type".

Quels sont les exemples spectacle est différentes façons que vous pouvez utiliser pour injecter les haricots dans des champs, des méthodes et des 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 cependant être un peu prudent avec les interfaces:

Cet autowiring échouera:

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

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

 @Autowired
 public void prepare( @Qualifier("bean1") Interface1 bean1,
     @Qualifier("bean2")  Interface1 bean2 ) { ... }
 16
Author: 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 faire 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{[7] } le paquet nom de com.movies à quel est le vrai nom du paquet et s'il s'agit d'une classe tierce, assurez-vous que le fichier jar approprié se trouve sur le chemin de classe):

<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 ça,

<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 ça,

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

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

 5
Author: 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;

    ...
}

Astuce d'annotation Spring Les haricots Spring peuvent être câblés par nom ou par type. @Autowire par défaut est une injection pilotée par type. L'annotation @ Qualifier spring peut être utilisée pour affiner davantage le câblage automatique. @Resource (javax.annotation.Ressource) l'annotation peut être utilisée pour le câblage par nom. Les Beans qui sont eux mêmes définis comme un type de collection ou de carte ne peuvent pas être injectés par @Autowired, car la correspondance de type ne leur est pas correctement applicable. Utilisez @Resource pour ces beans, en faisant référence à la collection spécifique ou au bean de carte par nom unique

 5
Author: aman, 2015-08-28 23:31:28