Il bean @Autowired è nullo quando viene fatto riferimento nel costruttore di un altro bean


89

Di seguito è mostrato uno snippet di codice in cui provo a fare riferimento al mio bean ApplicationProperties. Quando lo faccio riferimento dal costruttore è nullo, ma quando viene fatto riferimento da un altro metodo va bene. Fino ad ora non ho avuto problemi ad utilizzare questo bean autowired in altre classi. Ma questa è la prima volta che provo a usarlo nel costruttore di un'altra classe.

Nello snippet di codice sottostante applicationProperties è nullo quando viene chiamato dal costruttore, ma quando viene fatto riferimento nel metodo convert non lo è. Cosa mi manca

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

Di seguito è riportato uno snippet da 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");
  }

Risposte:


179

L'autowiring (link dal commento di Dunes) avviene dopo la costruzione di un oggetto. Pertanto non verranno impostati fino al completamento del costruttore.

Se è necessario eseguire del codice di inizializzazione, dovresti essere in grado di estrarre il codice dal costruttore in un metodo e annotare quel metodo con @PostConstruct.


3
Come si dice nella documentazione - static.springsource.org/spring/docs/2.5.x/api/org/…
Dunes

Grazie per il link, lo aggiungerò alla risposta per una facile ricerca.
nicholas.hauschild

2
Grazie, dovevo ancora trovare l'affermazione cruciale "I campi vengono iniettati subito dopo la costruzione di un fagiolo ...". Ho provato l'annotazione @PostConstruct ed è esattamente ciò di cui avevo bisogno.
hairyone

sarebbe anche bello pubblicare un link su @PostConstruct static.springsource.org/spring/docs/3.0.0.M3/reference/html/…
Timofey

@Tim Grazie! Ho aggiornato il link delle risposte alla versione Spring 3.2 e ho anche aggiunto una versione Spring 3.2 del tuo link.
nicholas.hauschild

44

Per avere dipendenze iniettate in fase di costruzione, devi avere il tuo costruttore contrassegnato con l' @Autowiredannunzio in questo modo.

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

2
In realtà penso che questa dovrebbe essere la risposta preferita. L'approccio di inserimento delle dipendenze basato sul costruttore è molto adatto per i componenti obbligatori. Utilizzando questo approccio la struttura della molla sarà anche in grado di rilevare le dipendenze cicliche dai componenti (poiché in A dipende da B, B dipende da C, C dipende da A). Lo stile di iniezione che utilizza setter o campi autowired è in grado di iniettare bean non completamente inizializzati nel tuo campo rendendo le cose un po 'più complicate.
Seakayone
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.