从static变量初始化到Spring/Spring boot的工具类静态变量注入

引入

写这篇博文,要从java.lang.ExceptionInInitializerError这个报错开始。简单的看上去,这是一个类初始化异常报错。但事实上并不是这样,这是由于调用某个static变量属性时而该属性没有初始化而导致的错误,所以,在debug模式下,你第二次再尝试调用操作static属性的方法时,可能就会抛出一个空指针异常了。据听请看这段代码。

Domain.java

public class Domain {

    private static Domain domain = new Domain();

    private static Map<String,String> domainMap = new HashMap<String
            ,String>();

    private Domain() {
        domainMap.put("isTrue","true");
    }

    public static Domain getInstance() {
        return domain;
    }
}


TestDomain.java

public class TestDomain {
    public static void main(String[] args) {
        String domainString = Domain.getInstance().toString();
        System.out.println(domainString);
    }
}

在执行调用的时候就会报错了!那原因是什么呢?
原因还是很简单的,在调用Domain静态方法时,由于两个变量都是静态变量,不会对它进行赋值,但会对变量按顺序进行初始化。所以先给domain初始化,这个时候调用私有构造函数,函数内已经用到了domainMap,而这个变量还没有初始化,进而抛出了没有初始化类的异常。
想要解决这个异常,两种方案。

  • 把domain和domainMap的变量声明位置调换,这样在调用私有构造函数时domainMap已经初始化了。
  • 将domain的构造函数公有化,并使外部调用来初始化,而不是声明时即初始化。当然这样并不符合工具类的使用方便,会造成浪费内存等后果。

渐进

之所以举上面这个例子,是因为它的构造很像工具类。
首先你得明白什么是工具类,简单来说它是一种可以不用初始化对象而直接调用其静态方法而达到某一些功能的以Utils或Helper结尾的类。说到这里,要声明一下,并不是所有的静态类都是推荐使用的,使用静态类的过程往往只是为了阅读方便和调用简单,但却不知会增加程序的耦合度,破坏设计模式等缺点。这里贴一篇文章写的很不错:如何摆脱工具类
而我们最终的问题是,如何在工具类中初始化赋值静态属性呢。项目环境是在spring框架下,举个例子:

XXXProperties.java

public class XXXProperties {

    private String staticParam1;

    private String staticParam2;

    public String getStaticParam1() {
        return staticParam1;
    }

    public void setStaticParam1(String staticParam1) {
        this.staticParam1 = staticParam1;
    }

    public String getStaticParam2() {
        return staticParam2;
    }

    public void setStaticParam2(String staticParam2) {
        this.staticParam2 = staticParam2;
    }

}

XXUtils.java

public class XXUtils {

    @Autowired //静态变量通过spring并不能直接注入,所以这样是会报错的
    private static XXXProperties xxxProperties;

    private static String do() {
        String xxxPropertiesSize = xxxProperties.getSize();
        return xxxPropertiesSize;
    }
}

当外部想要调用XXUtilsdo()时,发现xxxProperties并没有注入值,而我们去调用时,程序也自然会抛出文章开始说的异常。

怎么去注入呢?

方案

  1. 采用间接注入方式
//可以换成@Configuration,与@Inject配合使用
@Component
public class XXUtils {

    //可以换成@Inject
    @Resource
    private XXXProperties xxxPropertiesAutowired;

    private static XXXProperties xxxProperties;

    @PostConstruct
    public void init() {
       this.xxxProperties = xxxPropertiesAutowired;
    }
}

也可以使用在Spring Boot中使用 @ConfigurationProperties 注解 给出的注解方式,是针对spring-boot的。

  1. 将静态参数用beans提取,以键值对形式存储,在工具类中直接调用
配置

应用

其中

public class org.springframework.beans.factory.config.PropertyPlaceholderConfigurer extends org.springframework.beans.factory.config.PlaceholderConfigurerSupport
  1. 如果你不想提取bean,也可以直接读取file.
public class XMLConfig {
      private static final Logger logger = Logger.getLogger(XMLConfig.class);
      public static final String            FILEPATH         = "xmlconf.properties";
      public static long                    fileLastModified = 0;

      //属性文件xmlconf.properties中对应的各个键值对
      public static HashMap<String, String> paramsMap    = new HashMap<String, String>();

      public static HashMap<String, String> loadProperties(String file)
      {
          HashMap<String, String> map = new HashMap<String, String>();
          InputStream in = null;
          Properties p = new Properties();
          try
          {
              in = new BufferedInputStream(new FileInputStream(file));

              p.load(in);
          }
          catch (FileNotFoundException e)
          {
              logger.error(file + " is not exists!");
          }
          catch (IOException e)
          {
              logger.error("IOException when load " + file);
          }
          finally
          {
              if (in != null)
              {
                  try
                  {
                      in.close();
                  }
                  catch (IOException e)
                  {
                      logger.error("Close IO error!");
                  }
              }
          }

          Set<Entry<Object, Object>> set = p.entrySet();
          Iterator<Entry<Object, Object>> it = set.iterator();
          while (it.hasNext())
          {
              Entry<Object, Object> entry = it.next();
              String key = (String) entry.getKey();
              String value = (String) entry.getValue();
              logger.debug(key + "=" + value);
              // System.out.println(key + "=" + value);
              if (key != null && value != null)
              {
                  map.put(key.trim(), value.trim());
              }
          }

          return map;
      }

}
  1. 待你完善
    期待有更好的方法一起交流讨论。

参考

java.lang.ExceptionInInitializerError的原因

java.lang.ExceptionInInitializerError in Connection Factory

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,622评论 18 399
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,236评论 11 349
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,651评论 18 139
  • (一)Java部分 1、列举出JAVA中6个比较常用的包【天威诚信面试题】 【参考答案】 java.lang;ja...
    独云阅读 7,098评论 0 62
  • 虽然当时他还不知道书法以后有什么作用,但事实证明,叫不死的艺术修养是的苹果公司所有的产品都设计的非常漂亮。 在美国...
    王老刘阅读 199评论 0 0