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

89

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, c'est bien. Jusqu'à présent, je n'ai eu aucun problème à utiliser ce bean autowired dans d'autres classes. Mais c'est la première fois que j'essaye de l'utiliser dans le constructeur d'une autre classe.

Dans l'extrait de code ci-dessous, applicationProperties est null lorsqu'il est appelé à partir du constructeur, mais lorsqu'il est référencé dans la méthode de conversion, ce n'est pas le cas. Qu'est-ce que je rate

@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();
    ...

Vous trouverez ci-dessous un extrait d'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");
  }
poilu
la source

Réponses:

179

Le câblage automatique (lien depuis le commentaire Dunes) se produit après la construction d'un objet. Par conséquent, ils ne seront définis qu'après la fin du constructeur.

Si vous devez exécuter du code d'initialisation, vous devriez être en mesure d'extraire le code du constructeur dans une méthode et d'annoter cette méthode avec @PostConstruct.

nicholas.hauschild
la source
3
Comme il est dit dans la documentation - static.springsource.org/spring/docs/2.5.x/api/org/…
Dunes
Merci pour le lien, je l'ajouterai à la réponse pour une recherche facile.
nicholas.hauschild
2
Merci, je n'avais pas encore rencontré la déclaration cruciale "Les champs sont injectés juste après la construction d'un haricot ...". J'ai essayé l'annotation @PostConstruct et c'est exactement ce dont j'avais besoin.
poilu
serait également bien de publier un lien sur @PostConstruct static.springsource.org/spring/docs/3.0.0.M3/reference/html/…
Timofey
@Tim Merci! J'ai mis à jour le lien des réponses vers la version Spring 3.2, et j'ai également ajouté une version Spring 3.2 de votre lien.
nicholas.hauschild
44

Pour que les dépendances soient injectées au moment de la construction, vous devez avoir votre constructeur marqué avec l' @Autowiredannoation comme ceci.

@Autowired
public DocumentManager(IApplicationProperties applicationProperties) {
  this.applicationProperties = applicationProperties;
  startOOServer();
}
mR_fr0g
la source
2
En fait, je pense que cela devrait être la réponse préférée. L'approche d'injection de dépendances basée sur le constructeur est très bien adaptée aux composants obligatoires. En utilisant cette approche, le cadre de ressort sera également capable de détecter les dépendances cycliques des 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 auto-câblés est capable d'injecter des beans non entièrement initialisés dans votre champ, ce qui rend les choses un peu plus compliquées.
Seakayone