← Назад к вопросам

В чем Hibernate использует паттерн Factory

3.0 Senior🔥 141 комментариев
#ORM и Hibernate#SOLID и паттерны проектирования

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Factory паттерн в Hibernate

Hibernate активно использует паттерн Factory в нескольких местах. Это позволяет создавать объекты гибким образом, скрывая детали реализации. Рассмотрю основные места использования.

1. SessionFactory — главная фабрика в Hibernate

// SessionFactory - это фабрика для создания Session объектов

public class HibernateFactoryExample {
    // SessionFactory создаётся один раз при инициализации приложения
    private static final SessionFactory sessionFactory = 
        new Configuration()
            .configure("hibernate.cfg.xml")
            .addAnnotatedClass(User.class)
            .addAnnotatedClass(Order.class)
            .buildSessionFactory();  // ← Это Factory!
    
    public static Session openSession() {
        // SessionFactory используется как Factory для создания Session
        return sessionFactory.openSession();
    }
}

// Без Factory пришлось бы вручную создавать Connection, управлять ними
// SessionFactory скрывает всю сложность

Почему это Factory?

  • SessionFactory создаёт объекты Session
  • Скрывает детали создания (управление пулом соединений, кэширование и т.д.)
  • Позволяет менять реализацию без изменения клиентского кода

2. Dialect Factory

Hibernate поддерживает множество БД (MySQL, PostgreSQL, Oracle и т.д.). Для каждой БД нужны разные SQL диалекты:

// Hibernate использует Factory для создания правильного Dialect

public class DialectFactoryUsage {
    // В hibernate.cfg.xml
    // <property name="hibernate.dialect">
    //     org.hibernate.dialect.PostgreSQL95Dialect
    // </property>
    
    // Или через код
    Configuration config = new Configuration();
    config.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
    
    // Hibernate автоматически создаёт нужный Dialect
    Dialect dialect = config.getDialect();
    
    // Теперь Hibernate знает, как генерировать SQL для конкретной БД
    String sql = dialect.getAddColumnString();  // MySQL: ALTER TABLE ... ADD
}

// Под капотом Hibernate имеет что-то вроде:
public class DialectFactory {
    public static Dialect createDialect(String dialectClass) 
            throws HibernateException {
        try {
            return (Dialect) Class.forName(dialectClass).newInstance();
        } catch (ClassNotFoundException | InstantiationException e) {
            throw new HibernateException("Cannot create dialect: " + dialectClass, e);
        }
    }
}

3. EntityFactory при загрузке данных

Когда Hibernate загружает данные из БД, он должен создать объекты сущностей:

@Entity
public class User {
    @Id
    private Long id;
    
    @Column
    private String name;
    
    @Column
    private String email;
    
    // Hibernate использует отражение (Reflection) для создания объектов
}

// Когда выполняем запрос
public class EntityLoadingExample {
    public static void main(String[] args) {
        Session session = sessionFactory.openSession();
        
        // Hibernate загружает данные из БД
        // Результат: Row {id: 1, name: "John", email: "john@example.com"}
        
        // Потом Factory создаёт User объект
        User user = session.createQuery("from User where id = 1", User.class)
            .uniqueResult();
        // ↑ Factory использует конструктор и установку полей
    }
}

// Примерно вот так это выглядит внутри:
public class EntityFactory {
    public static <T> T createEntity(Class<T> entityClass, Object[] values) {
        try {
            T entity = entityClass.getConstructor().newInstance();  // Constructor Factory!
            
            // Установка значений через setters или reflection
            Field[] fields = entityClass.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                fields[i].setAccessible(true);
                fields[i].set(entity, values[i]);
            }
            
            return entity;
        } catch (Exception e) {
            throw new RuntimeException("Cannot create entity", e);
        }
    }
}

4. StatementFactory для создания SQL запросов

// Hibernate использует Factory для создания PreparedStatement объектов

public class StatementCreationExample {
    // Вместо того, чтобы вручную создавать Statement
    Connection conn = session.connection();
    PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?");
    
    // Hibernate использует свой Statement Factory
    // который добавляет логирование, кэширование, управление батчами и т.д.
}

5. ProxyFactory для ленивой загрузки

Одна из самых важных фабрик в Hibernate — ProxyFactory. Она создаёт прокси-объекты для ленивой загрузки:

@Entity
public class Order {
    @Id
    private Long id;
    
    @ManyToOne(fetch = FetchType.LAZY)  // Ленивая загрузка!
    private User user;
}

public class ProxyFactoryExample {
    public static void main(String[] args) {
        Session session = sessionFactory.openSession();
        
        // Загружаем заказ
        Order order = session.get(Order.class, 1L);
        // Пользователь ещё НЕ загружен! Вместо этого создан Proxy
        
        // Прокси создан ProxyFactory
        // Это объект, который выглядит как User, но загружает данные лениво
        
        System.out.println(order.getUser().getName());  // Только ЗДЕСЬ загружается
        // ProxyFactory создал подмену (прокси) User
    }
}

// Примерно так это реализовано
public class ProxyFactory {
    public static <T> T createLazyProxy(Class<T> targetClass, Long id, 
                                        LazyInitializer initializer) {
        // Используя Cglib или ByteBuddy создаём подмену
        // которая выглядит как T, но загружает данные на первое обращение
        
        return (T) Enhancer.create(targetClass, 
            (MethodInterceptor) (obj, method, args, proxy) -> {
                if (initializer.isInitialized()) {
                    return proxy.invokeSuper(obj, args);
                }
                
                // Загружаем данные из БД
                initializer.initialize();
                return proxy.invokeSuper(obj, args);
            });
    }
}

6. CacheFactory для создания кэшей

// Hibernate использует Factory для создания кэшей

public class CacheConfiguration {
    // В persistence.xml
    // <property name="hibernate.cache.provider_class"
    //     value="org.hibernate.cache.EhCacheProvider" />
    
    // Или через код
    @Cacheable
    @Entity
    public class User {
        @Id
        private Long id;
        private String name;
    }
    
    // CacheFactory создаёт подходящий кэш для User
    // Может быть EhCache, Infinispan, Hazelcast и т.д.
}

7. IdentifierGeneratorFactory

Для генерации ID используется Factory паттерн:

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)  // Factory!
    private Long id;
    
    private String name;
}

public class IdentifierGeneratorExample {
    // Hibernate использует IdentifierGeneratorFactory для создания
    // подходящего генератора ID на основе strategy
    
    // GenerationType.SEQUENCE → SequenceGenerator
    // GenerationType.IDENTITY → IdentityGenerator
    // GenerationType.UUID → UUIDGenerator
    // GenerationType.AUTO → выбирает подходящий
}

Диаграмма Factory использований в Hibernate

Hibernate Framework
    ├── SessionFactory (Factory для Session)
    │   └── Session (использует другие factories)
    │       ├── DialectFactory → Dialect (для конкретной БД)
    │       ├── EntityFactory → Entity объекты из БД
    │       ├── ProxyFactory → Lazy-loaded прокси
    │       ├── StatementFactory → PreparedStatement
    │       └── CacheFactory → Cache реализация
    │
    └── Configuration
        └── IdentifierGeneratorFactory → ID генератор

Практический пример всех factories вместе

public class HibernateFactoriesIntegration {
    public static void main(String[] args) {
        // 1. SessionFactory создаёт Session
        SessionFactory sessionFactory = new Configuration()
            .configure()  // Reads hibernate.cfg.xml
            .addAnnotatedClass(User.class)
            .addAnnotatedClass(Order.class)
            .buildSessionFactory();  // ← Factory!
        
        Session session = sessionFactory.openSession();  // ← Factory!
        
        // 2. Загружаем заказ
        Order order = session.get(Order.class, 1L);
        // - EntityFactory создал Order объект из строки БД
        // - ProxyFactory создал прокси User (если FetchType.LAZY)
        // - DialectFactory уже выбрал правильный SQL диалект
        // - IdentifierGeneratorFactory создал генератор ID
        // - StatementFactory создал и управляет PreparedStatement
        // - CacheFactory управляет кэшированием
        
        // 3. Обращаемся к ленивому User
        System.out.println(order.getUser().getName());
        // ProxyFactory инициализировал прокси и загрузил данные
        
        session.close();
        sessionFactory.close();
    }
}

Зачем Hibernate использует Factory

  1. Абстракция деталей — клиентский код не знает, как создаются объекты
  2. Гибкость — легко менять реализацию (например, Dialect для другой БД)
  3. Управление жизненным циклом — Factory может управлять кэшированием, пулингом и т.д.
  4. Оптимизация — Factory может создавать оптимальные объекты для конкретной ситуации
  5. Расширяемость — можно создавать собственные Factory реализации

Вывод: Factory паттерн в Hibernate позволяет скрыть сложность создания различных объектов и обеспечивает гибкость в выборе реализаций для разных БД, кэшей и стратегий загрузки данных.

В чем Hibernate использует паттерн Factory | PrepBro