@Autowired bean имеет значение null при ссылке в конструкторе другого bean-компонента

91

Ниже показан фрагмент кода, в котором я пытаюсь сослаться на свой bean-компонент ApplicationProperties. Когда я ссылаюсь на него из конструктора, он имеет значение null, но при ссылке из другого метода это нормально. До сих пор у меня не было проблем с использованием этого autowired bean-компонента в других классах. Но я впервые пробовал использовать его в конструкторе другого класса.

В приведенном ниже фрагменте кода applicationProperties имеет значение null при вызове из конструктора, но при ссылке в методе convert это не так. Что мне не хватает

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

Ниже приведен фрагмент из 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");
  }
волосатый
источник

Ответы:

183

Автономный монтаж (ссылка из комментария Дюны) происходит после постройки объекта. Следовательно, они не будут установлены до тех пор, пока конструктор не завершит работу.

Если вам нужно запустить какой-то код инициализации, вы сможете вытащить код из конструктора в метод и аннотировать этот метод с помощью @PostConstruct.

Николай Хаушильд
источник
3
Как написано в документации - static.springsource.org/spring/docs/2.5.x/api/org/…
Dunes
Спасибо за ссылку, добавлю в ответ для удобства поиска.
nicholas.hauschild
2
Спасибо, мне еще не приходилось сталкиваться с важным утверждением «Поля вводятся сразу после построения bean-компонента ...». Я пробовал аннотацию @PostConstruct, и это именно то, что мне нужно.
hairyone
также неплохо было бы разместить ссылку на @PostConstruct static.springsource.org/spring/docs/3.0.0.M3/reference/html/…
Тимофей
@Tim Спасибо! Я обновил ссылку с ответами на версию Spring 3.2, а также добавил версию Spring 3.2 вашей ссылки.
nicholas.hauschild
45

Чтобы зависимости вводились во время построения, вам нужно, чтобы ваш конструктор был помечен @Autowiredаннотацией, подобной этой.

@Autowired
public DocumentManager(IApplicationProperties applicationProperties) {
  this.applicationProperties = applicationProperties;
  startOOServer();
}
mR_fr0g
источник
2
На самом деле я думаю, что это должен быть предпочтительный ответ. Подход с внедрением зависимостей на основе конструктора очень хорошо подходит для обязательных компонентов. Используя этот подход, Spring framework также сможет обнаруживать циклические зависимости от компонентов (поскольку в A зависит от B, B зависит от C, C зависит от A). Стиль внедрения с использованием сеттеров или полей с автоматическим подключением может вводить не полностью инициализированные bean-компоненты в ваше поле, что делает вещи немного более беспорядочными.
Seakayone
0

Да, оба ответа верны.

Если честно, эта проблема на самом деле похожа на сообщение Почему мое поле Spring @Autowired имеет значение null? .

Основная причина ошибки может быть объяснена в справочном документе Spring ( Autowired ), как показано ниже

Автоматизированные поля

Поля вводятся сразу после создания bean-компонента, до вызова каких-либо методов конфигурации.

Но настоящая причина этого утверждения в документе Spring - это жизненный цикл компонента Spring. Это часть философии дизайна Spring.

Это обзор жизненного цикла Spring Bean : введите описание изображения здесь Bean должен быть инициализирован, прежде чем он может быть введен с такими свойствами, как field. Так устроены бобы, вот и настоящая причина.

Надеюсь, этот ответ будет вам полезен!

чжаоци
источник