web-dev-qa-db-fra.com

spring @Autowire property vs setter

Quelle est la différence entre anotate @Autowired à une propriété ou le faire dans le setter?

Autant que je sache, ils ont tous deux le même résultat, mais y a-t-il une raison d'utiliser l'un sur l'autre?

MISE À JOUR (pour être plus concis)

Y a-t-il une différence entre cela

package com.tutorialspoint;

import org.springframework.beans.factory.annotation.Autowired;

public class TextEditor {
   private SpellChecker spellChecker;

   @Autowired
   public void setSpellChecker( SpellChecker spellChecker ){
      this.spellChecker = spellChecker;
   }

   public void spellCheck() {
      spellChecker.checkSpelling();
   }
}

et ça

package com.tutorialspoint;

import org.springframework.beans.factory.annotation.Autowired;

public class TextEditor {
   @Autowired
   private SpellChecker spellChecker;

   public TextEditor() {
      System.out.println("Inside TextEditor constructor." );
   }

   public void spellCheck(){
      spellChecker.checkSpelling();
   }
}
29
luso

Avec @Autowired annotation, vous n'avez pas besoin d'une méthode de définition. Une fois que le constructeur de votre bean a fini d'allouer/créer l'objet, Spring va scanner cette annotation et injecter les instances d'objet que vous avez annotées.

Alors que si vous avez setter et si vous utilisez toujours la configuration xml, vous définiriez explicitement les propriétés.

Cela dit, vous pouvez annoter votre constructeur et votre méthode de définition avec une annotation auto-câblée que je préférerais car cela me donnerait plus de souplesse pour m'éloigner de Spring (bien que je ne le fasse pas).

19
SMA

Parfois, vous avez besoin d'une instance de classe A, mais vous ne stockez pas A dans le champ de la classe. Vous avez juste besoin de A pour effectuer une opération ponctuelle. Ou, vous utilisez A pour obtenir une instance de B et vous stockez B dans le champ.

Dans ces cas, un fil automatique setter (ou constructeur) vous conviendra mieux. Vous n'aurez pas de champs de niveau classe inutilisés.

Exemple concret: vous devez construire RabbitTemplate (un objet qui envoie des messages à RabbitMQ) Pour le construire, vous avez besoin ConnectionFactory http://docs.spring.io/spring-amqp/docs/latest_ga/api/org/springframework/amqp/rabbit/core/RabbitTemplate.html#RabbitTemplate- org.springframework.amqp.rabbit.connection.ConnectionFactory -

Vous n'avez pas besoin de stocker cette ConnectionFactory. Dans ce cas, un code qui ressemble à ceci:

Class MyClass {
private RabbitTemplate template;

@Autowired 
void setConnectionFactory(ConnectionFactory c) {
    template=new RabbitTemplate(c);
}
}

... vous servira mieux que le câblage automatique du champ ConnectionFactory .

Dans cet exemple, le câblage automatique au niveau du constructeur serait encore mieux, car votre objet sera toujours entièrement construit. Il sera clair que ConnectionFactory est une dépendance obligatoire, pas facultative.

17
Bartosz Bilicki

Si vous le pouvez, vous devez éviter le passeur. Si vous n'en avez pas besoin, c'est mieux quand il n'existe pas, non?

Personnellement, je préfère que Guice me permette d'écrire

public class TextEditor {
   private final SpellChecker spellChecker;

   @Inject public TextEditor(SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }

   public void spellCheck(){
      spellChecker.checkSpelling();
   }
}

Cela va plus loin: avec un champ final, je sais qu'il ne changera jamais et j'obtiens garantie de visibilité multithreading .

1
maaartinus

Le câblage automatique fonctionne mieux lorsqu'il est utilisé de manière cohérente dans un projet. Si le câblage automatique n'est pas utilisé en général, il peut être déroutant pour les développeurs de l'utiliser pour câbler uniquement une ou deux définitions de bean. Avec @Autowired sur un champ, vous n'avez pas besoin d'une méthode de définition, qui, d'une part, rend la classe plus petite et plus facile à lire, mais d'autre part rend la moquerie de la classe un peu plus laide.

Les dépendances explicites dans les paramètres de propriété et de constructeur-arg remplacent toujours le câblage automatique. Vous ne pouvez pas câbler automatiquement les propriétés dites simples telles que les primitives, les chaînes et les classes (et les tableaux de ces propriétés simples). Cette limitation est intentionnelle.

Le câblage automatique est moins précis que le câblage explicite. Spring prend soin d'éviter de deviner en cas d'ambiguïté qui pourrait avoir des résultats inattendus, les relations entre vos objets gérés par Spring ne sont plus documentées explicitement.

Les informations de câblage peuvent ne pas être disponibles pour les outils susceptibles de générer de la documentation à partir d'un conteneur Spring.

Plusieurs définitions de bean dans le conteneur peuvent correspondre au type spécifié par la méthode setter ou l'argument constructeur à câbler automatiquement. Pour les tableaux, les collections ou les cartes, ce n'est pas nécessairement un problème. Cependant, pour les dépendances qui attendent une seule valeur, cette ambiguïté n'est pas résolue arbitrairement. Si aucune définition de bean unique n'est disponible, une exception est levée.

1

Si tu utilises @Autowired annotation sur une propriété, spring lancera la propriété en utilisant spring.xml. Vous n'avez pas besoin de setter dans ce cas.

Si tu utilises @Autowired annotation sur un setter, vous spécifiez au printemps qu'il doit initier cette propriété en utilisant cette méthode setter où vous pouvez ajoutez votre code personnalisé, comme initialisant une autre propriété avec cette propriété .

tilisation avec l'exemple: Dans le cas de l'utilisation d'opérations DAO à l'aide de JdbcTemplate, vous avez besoin de DataSource comme entrée de JdbcTemplate, mais DataSource n'est pas requis en tant que propriété en soi. Vous pouvez donc utiliser DataSource Setter pour initialiser JdbcTempate en câblant automatiquement DataSource Setter. Veuillez voir le code ci-dessous:

class DaoDemo{
   //@Autowired
   //private DataSource dataSource;
   private JdbcTemplate jdbcTemplate;

   @Autowired
   public void setDataSource(DataSource dataSource){
     //this.dataSource = dataSource;  
     this.jdbcTemplate = new JdbcTemplate(dataSource);
   }

   public int getTableRowCount(){
      String sql = "SELECT COUNT(*) FROM DEMOTABLE";
      //jdbcTemplate.setDataSource(dataSource);    //No need to do this as its done in DataSource Setter now.
      return jdbcTemplate.queryForObject(sql,Integer.class);

}

Dans le code ci-dessus, la seule utilisation de dataSource était de se faire passer dans JdbcTemplate. Donc, créer une propriété de dataSource n'a pas de sens ici. Donc, utilisez simplement la méthode @Autowired on setter du bean DataSource pour obtenir son entrée à partir de spring.xml et l'utiliser à ce moment-là.

1
Sahil Chhabra

Il y a un cas où l'utilisation de @Autowired sur une propriété FACULTATIVE ne fonctionnerait pas.

Si vous souhaitez effectuer une initialisation à l'aide de cette propriété, il se peut qu'elle ne soit pas définie avant l'appel du constructeur, et comme elle est facultative, vous ne pouvez pas la placer comme argument dans le constructeur.

Dans ce cas, il est préférable d'utiliser une méthode de définition @Autowired, afin que vous puissiez effectuer l'initialisation une fois que la propriété est câblée automatiquement.

0
AdamSkwersky