O bean @Autowired é nulo quando referenciado no construtor de outro bean

89

Abaixo, é mostrado um trecho de código onde tento fazer referência ao meu bean ApplicationProperties. Quando eu faço referência a partir do construtor, ele é nulo, mas quando referenciado a partir de outro método, está bem. Até agora, não tive nenhum problema em usar este bean autowired em outras classes. Mas esta é a primeira vez que tento usá-lo no construtor de outra classe.

No trecho de código abaixo, applicationProperties é nulo quando chamado do construtor, mas não é quando referenciado no método convert. O que estou perdendo

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

Abaixo está um snippet 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");
  }
peludo
fonte

Respostas:

179

Autowiring (link do comentário de Dunas) acontece após a construção de um objeto. Portanto, eles não serão definidos até que o construtor seja concluído.

Se você precisar executar algum código de inicialização, deverá ser capaz de puxar o código do construtor para um método e anotar esse método com @PostConstruct.

nicholas.hauschild
fonte
3
Como está escrito na documentação - static.springsource.org/spring/docs/2.5.x/api/org/…
Dunes
Obrigado pelo link, vou adicioná-lo à resposta para facilitar a localização.
nicholas.hauschild
2
Obrigado, eu ainda não tinha encontrado a declaração crucial "Os campos são injetados logo após a construção de um feijão ..." Eu tentei a anotação @PostConstruct e é exatamente o que eu precisava.
cabeludo
também seria bom postar um link sobre @PostConstruct static.springsource.org/spring/docs/3.0.0.M3/reference/html/…
Timofey
Obrigado @Tim! Eu atualizei o link de respostas para a versão Spring 3.2 e também adicionei uma versão Spring 3.2 do seu link.
nicholas.hauschild
44

Para ter dependências injetadas no momento da construção, você precisa ter seu construtor marcado com a @Autowiredanotação como tal.

@Autowired
public DocumentManager(IApplicationProperties applicationProperties) {
  this.applicationProperties = applicationProperties;
  startOOServer();
}
mR_fr0g
fonte
2
Na verdade, acho que essa deve ser a resposta preferida. A abordagem de injeção de dependência baseada em construtor é muito adequada para componentes obrigatórios. Usando esta abordagem, o framework Spring também será capaz de detectar dependências cíclicas nos componentes (como em A depende de B, B depende de C, C depende de A). O estilo de injeção usando setters ou campos autowired é capaz de injetar beans não totalmente inicializados em seu campo, tornando as coisas um pouco mais confusas.
Seakayone