103 votes

Le bean @Autowired est nul lorsqu'il est référencé dans le constructeur d'un autre bean.

Vous trouverez ci-dessous un extrait de code dans lequel j'essaie de référencer mon bean ApplicationProperties. Lorsque je le référence à partir du constructeur, il est nul, mais lorsqu'il est référencé à partir d'une autre méthode, tout va bien. Jusqu'à présent, je n'ai eu aucun problème à utiliser ce bean autoprogrammé dans d'autres classes. Mais c'est la première fois que j'ai essayé de l'utiliser dans le constructeur d'une autre classe.

Dans l'extrait de code ci-dessous, applicationProperties est nul lorsqu'il est appelé depuis le constructeur, mais lorsqu'il est référencé dans la méthode convert, il ne l'est pas. Qu'est-ce que j'ai manqué ?

@Component
public class DocumentManager implements IDocumentManager {

  private Log logger = LogFactory.getLog(this.getClass());
  private OfficeManager officeManager = null;
  private ConverterService converterService = null;

  @Autowired
  private IApplicationProperties applicationProperties;

  // If I try and use the Autowired applicationProperties bean in the constructor
  // it is null ?

  public DocumentManager() {
  startOOServer();
  }

  private void startOOServer() {
    if (applicationProperties != null) {
      if (applicationProperties.getStartOOServer()) {
        try {
          if (this.officeManager == null) {
            this.officeManager = new DefaultOfficeManagerConfiguration()
              .buildOfficeManager();
            this.officeManager.start();
            this.converterService = new ConverterService(this.officeManager);
          }
        } catch (Throwable e){
          logger.error(e);  
        }
      }
    }
  }

  public byte[] convert(byte[] inputData, String sourceExtension, String targetExtension) {
    byte[] result = null;

    startOOServer();
    ...

Voici un extrait de ApplicationProperties ...

@Component
public class ApplicationProperties implements IApplicationProperties {

  /* Use the appProperties bean defined in WEB-INF/applicationContext.xml
   * which in turn uses resources/server.properties
   */
  @Resource(name="appProperties")
  private Properties appProperties;

  public Boolean getStartOOServer() {
    String val = appProperties.getProperty("startOOServer", "false");
    if( val == null ) return false;
    val = val.trim();
    return val.equalsIgnoreCase("true") || val.equalsIgnoreCase("on") || val.equalsIgnoreCase("yes");
  }

197voto

nicholas.hauschild Points 21796

Câblage automatique (lien du commentaire de Dunes) se produit après la construction d'un objet. Par conséquent, ils ne seront pas définis avant la fin du constructeur.

Si vous avez besoin d'exécuter du code d'initialisation, vous devriez être en mesure d'intégrer le code du constructeur dans une méthode, et d'annoter cette méthode avec la balise @PostConstruct .

3 votes

Comme il est dit dans les docs -- static.springsource.org/spring/docs/2.5.x/api/org/

0 votes

Merci pour le lien, je l'ajouterai à la réponse pour le trouver facilement.

3 votes

Merci, je n'étais pas encore tombé sur l'affirmation cruciale "Les champs sont injectés juste après la construction d'un bean...". J'ai essayé l'annotation @PostConstruct et c'est exactement ce dont j'avais besoin.

58voto

mR_fr0g Points 3534

Pour que les dépendances soient injectées au moment de la construction, il faut que votre constructeur soit marqué par l'attribut @Autowired annoation ainsi.

@Autowired
public DocumentManager(IApplicationProperties applicationProperties) {
  this.applicationProperties = applicationProperties;
  startOOServer();
}

2 votes

En fait, je pense que cela devrait être la réponse préférée. L'approche de l'injection de dépendances basée sur les constructeurs est très bien adaptée aux composants obligatoires. En utilisant cette approche, le framework Spring sera également capable de détecter les dépendances cycliques sur les composants (comme dans A dépend de B, B dépend de C, C dépend de A). Le style d'injection utilisant des setters ou des champs autowired est capable d'injecter des beans non complètement initialisés dans votre champ, rendant les choses un peu plus désordonnées.

3voto

zhaocy Points 56

Oui, les deux réponses sont correctes.

Pour être honnête, ce problème est en fait similaire au post Pourquoi mon champ Spring @Autowired est-il nul ? .

La cause première de l'erreur peut être expliquée dans le document de référence de Spring ( Autocommandé ), comme suit:

Champs automatiques

Les champs sont injectés juste après la construction d'un bean, avant que les méthodes de configuration ne soient invoquées. méthodes de configuration soient invoquées.

Mais la véritable raison de cette déclaration dans le document de Spring est la suivante Cycle de vie du haricot au printemps. Cela fait partie de la philosophie de conception de Spring.

C'est Aperçu du cycle de vie des beans de Spring : enter image description here Le haricot doit d'abord être initialisé avant de pouvoir être injecté avec des propriétés telles que le champ. C'est ainsi que les beans sont conçus, c'est donc la vraie raison.

J'espère que cette réponse vous sera utile !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X