Как удалить запах кода: getSessionFactory, создавать SessionFactory только при необходимости - PullRequest
0 голосов
/ 12 июня 2018

Я использую 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 Ответ

0 голосов
/ 12 июня 2018

Я не уверен, что предупреждение компилятора (возможно, выданное IDE, а не javac) связано с модификатором static getFactory().

На самом деле getFactory() реализация объявляет оператор switch с default регистром, который возвращает null:

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

Так что getFactory() действительно может вернуть null, еслипереданный параметр не позволяет войти в один из предыдущих случаев.

Но я думаю, что основной проблемой getFactory() является отсутствие безопасности потоков.Действительно, если несколько потоков обращаются к нему одновременно, вы можете создать несколько сеансов и, возможно, создать несовместимое состояние.
В качестве альтернативы, для создания сеансов по требованию, вы можете использовать особый вариант шаблона singleton: инициализацияидиома держателя по требованию :

В разработке программного обеспечения идиома держателя инициализации по требованию (шаблон проектирования) представляет собой синглтон с отложенной загрузкой.Во всех версиях Java эта идиома обеспечивает безопасную высококонкурентную ленивую инициализацию с хорошей производительностью.

...