代码之家  ›  专栏  ›  技术社区  ›  EliteRaceElephant

如何去除代码气味:getsessionfactory,只在必要时创建sessionfactory

  •  1
  • EliteRaceElephant  · 技术社区  · 6 年前

    我使用hibernate来处理到数据库的连接。我有几个连接到不同模式的会话工厂。

    在启动时生成所有sessionfactory至少需要60秒。所以我只有在必要时才建造它们:

    public class HibernateUtil {
        private static SessionFactory factory_db1;
        private static SessionFactory factory_db2;
        //...
    
        public enum DbSchema {
          db1, db2 //...
        }        
    
        private createSessionFactory(Configuration conf){
        //...
        }
    
        public static SessionFactory getFactory(DbSchema dbSchema) {
    
          try {
            switch (dbSchema) {
                case db1:
                    if (factory_db1== null){
                        Configuration conf = new Configuration().configure(HIBERNATE_CFG_DB1);
                        factory_db1= createSessionFactory(conf);
                    }
                    return factory_db1;
                case db2:
                    if (factory_db2 == null){
                        Configuration conf = new Configuration().configure(HIBERNATE_CFGXML_DB2);
                        factory_ooarchive = createSessionFactory(conf);
                    }
                    return factory_ooarchive;
                //... more factories created
                default:
                    assert false : "Switch default should not be reachable.";
                    return null;
            }
          } catch (Throwable ex) {
            log.error("Failed to initialize SessionFactory." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }
    

    现在当我进入这个工厂时:

    Session session = HibernateUtil.getFactory(db1).openSession();
    // **Compiler warning: method invocation may produce java.lang.nullpointerexception**
    

    只有通过getFactory()方法才能获得工厂,因此我认为NPE永远不可能。我知道问题是工厂实例变量的静态关键字,并且在构造函数中没有初始化。我不希望这个“总是开着”的初始化!它只应在需要时初始化至少一次。

    我读了一些设计模式和代码质量方面的书,但是我很难实现我学到的东西。我想我创造了一种代码气味。我该如何修复这个设计?请解释我的错误和为什么我的选择有问题。

    1 回复  |  直到 6 年前
        1
  •  1
  •   davidxxx    6 年前

    我不确定编译器警告(可能是由IDE发出的,而不是 javac )与 static 修饰语 getFactory() .

    事实上 GETFIFESY() 实现声明 switch 有一个 default 返回的案例 null :

    default:
        assert false : "Switch default should not be reachable.";
        return null;
    

    所以 GETFIFESY() 可能真的会回来 无效的 如果传递的参数不允许在前面的情况下输入。

    但我认为 GETFIFESY() 是它缺乏线程安全性。实际上,如果多个线程同时访问它,则可以创建多个会话,并可能生成不一致的状态。
    另外,要按需创建会话,可以使用特定风格的单例模式: the initialization-on-demand holder idiom :

    在软件工程中,按需初始化保持器(design 模式)习语是一个延迟加载的单例。在所有版本的Java中, 这个习惯用法允许安全、高度并发的惰性初始化 表现不错。