问题描述

闲话少叙,先上代码。

public function main() {
  Util util = new Util();
  util.print();
}


public class Util {

  public static provider = new Provider();

  public Util() {
    # do sth
  }

  public void print() {
    # print sth
  }
}

public function Provider() {
  
  public Provider() {
    loadData();
  }

  private void loadData() {
    # load data
  }
}

大概使用逻辑是这样,在调用入口,实例化Util对象并调用他的print方法。 这个时候,获取到了一个runtime exception:class Util not defined。

类明明就摆在那里,为什么会报异常呢? 大家如果了解了类静态成员变量的初始化过程,就一眼看出来问题。

首先,provider是在Util类被加载的时候初始化的,要早于Util的实例化。

其次,如果provider初始化失败,会导致Util类加载失败,在实例化的时候就会抛异常。

问题的直接原因是在Provider的构造过程,由于构造函数执行了loadData的动作,这里就存在一些不确定因素,会导致错误的发生,从而影响到了Util的加载。

改进思路

精简类初始化的过程,优先保证对象能实例化成功,从而再执行数据加载的逻辑。可以利用Spring的PostConstruct注解来实现实例化和数据加载动作的分离。

public function main() {
  Util util = new Util();
  util.print();
}


public class Util {

  @Resource
  public Provider provider;

  public Util() {
    # do sth
  }

  public void print() {
    # print sth
  }
}

@Component
public function Provider() {
  
  @PostConstruct
  private void loadData() {
    # load data
  }
}

这样,就将问题暴露在运行时,就不会将问题隐藏的那么深了。

总结一下,

第一,尽量不要在构造函数里执行太多的业务逻辑,以及数据初始化的动作。

第二,对象示例谨慎持有静态数据。