@Autowired bean ma wartość null, gdy odwołuje się do konstruktora innego komponentu bean

91

Poniżej pokazano fragment kodu, w którym próbuję odwołać się do mojego komponentu bean ApplicationProperties. Kiedy odwołuję się do niego z konstruktora, jest on pusty, ale w przypadku odwołania z innej metody jest w porządku. Do tej pory nie miałem problemu z używaniem tej automatycznej fasoli w innych klasach. Ale to pierwszy raz, kiedy próbowałem go użyć w konstruktorze innej klasy.

W poniższym fragmencie kodu applicationProperties ma wartość null, gdy jest wywoływana z konstruktora, ale w przypadku odwołania w metodzie konwersji tak nie jest. Czego mi brakuje

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

Poniżej znajduje się fragment z 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");
  }
hairyone
źródło

Odpowiedzi:

182

Autowiring (link z komentarza Dunes) ma miejsce po zbudowaniu obiektu. Dlatego nie zostaną ustawione przed zakończeniem pracy konstruktora.

Jeśli potrzebujesz uruchomić kod inicjujący, powinieneś być w stanie wciągnąć kod z konstruktora do metody i dodać adnotację do tej metody za pomocą @PostConstruct.

nicholas.hauschild
źródło
3
Jak jest napisane w dokumentacji - static.springsource.org/spring/docs/2.5.x/api/org/…
Dunes
Dzięki za link, dodam go do odpowiedzi dla łatwego znalezienia.
nicholas.hauschild
2
Dziękuję, nie spotkałem się jeszcze z kluczowym stwierdzeniem „Pola są wstrzykiwane zaraz po zbudowaniu fasoli…”. Wypróbowałem adnotację @PostConstruct i właśnie tego potrzebowałem.
hairyone
byłoby również miło opublikować link o @PostConstruct static.springsource.org/spring/docs/3.0.0.M3/reference/html/ ...
Timofey
@Tim Thanks! Zaktualizowałem link odpowiedzi do wersji Spring 3.2, a także dodałem wersję linku Spring 3.2.
nicholas.hauschild
45

Aby zależności były wstrzykiwane w czasie budowy, musisz mieć swój konstruktor oznaczony takim @Autowiredadnotacją.

@Autowired
public DocumentManager(IApplicationProperties applicationProperties) {
  this.applicationProperties = applicationProperties;
  startOOServer();
}
mR_fr0g
źródło
2
Właściwie uważam, że to powinna być preferowana odpowiedź. Podejście do wstrzykiwania zależności oparte na konstruktorze jest bardzo dobrze dostosowane do obowiązkowych składników. Stosując to podejście, szkielet sprężynowy będzie również w stanie wykryć cykliczne zależności od komponentów (jak w A zależy od B, B zależy od C, C zależy od A). Styl wtrysku używający seterów lub pól autowired jest w stanie wstrzyknąć nie w pełni zainicjalizowane ziarna do twojego pola, co powoduje trochę bałaganu.
Seakayone