【问题标题】:@Autowired bean is null when referenced in the constructor of another bean@Autowired bean 在另一个 bean 的构造函数中引用时为空
【发布时间】:2011-09-14 05:24:40
【问题描述】:

下面显示的是一段代码,我尝试在其中引用我的 ApplicationProperties bean。当我从构造函数引用它时,它是空的,但是当从另一个方法引用它时它很好。到目前为止,我在其他类中使用这个自动装配的 bean 没有问题。但这是我第一次尝试在另一个类的构造函数中使用它。

在下面的代码 sn-p 中,从构造函数调用时 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 的 s sn-p ...

@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");
  }

【问题讨论】:

    标签: java spring autowired


    【解决方案1】:

    Autowiring(来自 Dunes 评论的链接)发生在对象构造之后。因此,在构造函数完成之前不会设置它们。

    如果你需要运行一些初始化代码,你应该可以将构造函数中的代码拉到一个方法中,并用@PostConstruct注释该方法。

    【讨论】:

    【解决方案2】:

    要在构造时注入依赖项,您需要将构造函数标记为 @Autowired 注释,如下所示。

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

    【讨论】:

    • 其实我认为这应该是首选的答案。基于构造函数的依赖注入方法非常适合强制组件。使用这种方法,spring 框架也将能够检测到组件的循环依赖(如 A 依赖于 B,B 依赖于 C,C 依赖于 A)。使用 setter 或自动装配字段的注入样式能够将未完全初始化的 bean 注入到您的字段中,从而使事情变得更加混乱。
    【解决方案3】:

    是的,两个答案都是正确的。

    说实话,这个问题其实和Why is my Spring @Autowired field null?这个帖子很像。

    错误的根源可以在Spring参考文档(Autowired)中解释,如下:

    自动装配字段

    在构建 bean 之后,在任何之前注入字段 配置方法被调用。

    但Spring doc中这句话背后的真正原因是Spring中的Bean的生命周期。这是 Spring 设计理念的一部分。

    这是Spring Bean Lifecycle Overview Bean需要先初始化,才能注入field等属性。这就是 bean 的设计方式,所以这才是真正的原因。

    希望这个回答对你有帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多