El bean @Autowired es nulo cuando se hace referencia en el constructor de otro bean

89

A continuación se muestra un fragmento de código en el que intento hacer referencia a mi bean ApplicationProperties. Cuando lo hago referencia desde el constructor, es nulo, pero cuando se hace referencia a él desde otro método está bien. Hasta ahora no he tenido ningún problema al usar este bean autowired en otras clases. Pero esta es la primera vez que intento usarlo en el constructor de otra clase.

En el fragmento de código siguiente, applicationProperties es nulo cuando se llama desde el constructor, pero cuando se hace referencia en el método de conversión no lo es. Qué me estoy perdiendo

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

A continuación se muestra un fragmento 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
fuente

Respuestas:

179

El cableado automático (enlace del comentario de Dunes) ocurre después de la construcción de un objeto. Por lo tanto, no se establecerán hasta que el constructor haya finalizado.

Si necesita ejecutar algún código de inicialización, debería poder extraer el código del constructor en un método y anotar ese método con @PostConstruct.

nicholas.hauschild
fuente
3
Como dice en los documentos - static.springsource.org/spring/docs/2.5.x/api/org/…
Dunes
Gracias por el enlace, lo agregaré a la respuesta para encontrarlo fácilmente.
nicholas.hauschild
2
Gracias, todavía tenía que encontrarme con la afirmación crucial "Los campos se inyectan justo después de la construcción de un frijol ...". Probé la anotación @PostConstruct y es exactamente lo que necesitaba.
hairyone
También sería bueno publicar un enlace sobre @PostConstruct static.springsource.org/spring/docs/3.0.0.M3/reference/html/…
Timofey
@Tim ¡Gracias! Actualicé el enlace de respuestas a la versión Spring 3.2 y también agregué una versión Spring 3.2 de su enlace.
nicholas.hauschild
44

Para que las dependencias se inyecten en el momento de la construcción, debe tener su constructor marcado con la @Autowiredanotación como tal.

@Autowired
public DocumentManager(IApplicationProperties applicationProperties) {
  this.applicationProperties = applicationProperties;
  startOOServer();
}
mR_fr0g
fuente
2
De hecho, creo que esta debería ser la respuesta preferida. El enfoque de inyección de dependencia basado en constructor es muy adecuado para componentes obligatorios. Usando este enfoque, el marco de resorte también podrá detectar dependencias cíclicas de los componentes (como en A depende de B, B depende de C, C depende de A). El estilo de inyección que usa setters o campos autowired es capaz de inyectar beans no completamente inicializados en su campo, haciendo las cosas un poco más complicadas.
Seakayone