Спецификация JPA в Spring, доступная в пакете org.springframework.orm.jpa, содержит комплексные средства поддержки Java Persistence API аналогично интеграции с Hibernate, при этом учитывая базовую реализацию для предоставления дополнительных функций.

Три варианта настройки JPA в окружении Spring

Поддержка JPA в Spring предполагает три способа настройки EntityManagerFactory из JPA, которая используется приложением для получения диспетчера сущностей.

  • Использование LocalEntityManagerFactoryBean

  • Получение EntityManagerFactory из JNDI

  • Использование LocalContainerEntityManagerFactoryBean

Использование LocalEntityManagerFactoryBean

Этот вариант можно использовать только в простых окружениях развертывания, таких как автономные приложения и интеграционные тесты.

LocalEntityManagerFactoryBean создает фабрику EntityManagerFactory, подходящую для простых окружений развертывания, где приложение использует только JPA для доступа к данным. Бин-фабрика использует механизм автоматического определения PersistenceProvider из JPA (в соответствии с начальной загрузкой JPA в Java SE) и в большинстве случаев требует задать только имя единицы сохраняемости. В следующем примере на XML сконфигурирован такой бин:

<beans>
    <bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="myPersistenceUnit"/>
    </bean>
</beans>

Эта форма развертывания JPA является самой простой и самой ограниченной. Ссылаться на существующее определение бина DataSource из JDBC нельзя, а поддержка глобальных транзакций отсутствует. Кроме того, связывание (преобразование байт-кода) постоянных классов зависит от конкретного поставщика, и часто требуется задать конкретного агента JVM при запуске. Этой опции будет достаточно только для автономных приложений и тестовых окружений, для которых разработана спецификация JPA.

Получение EntityManagerFactory из JNDI

Этот вариант можно использовать при развертывании на сервере Java EE. Проверьте документацию для вашего сервера, чтобы узнать, как развернуть кастомный поставщик JPA на вашем сервере, что позволит использовать поставщик, отличный от поставщика сервера по умолчанию.

Получение EntityManagerFactory из JNDI (например, в окружении Java EE) – это вопрос изменения конфигурации XML, как показано в следующем примере:

<beans>
    <jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/>
</beans>

Это действие предполагает стандартную начальную загрузку Java EE. Сервер Java EE автоматически обнаруживает единицы сохраняемости (по сути, файлы META-INF/persistence.xml в jar-файлах приложений) и записи persistence-unit-ref в дескрипторе развертывания Java EE (например, web.xml) и определяет местоположение контекста именования окружения для этих единиц сохраняемости.

В таком сценарии развертывание единиц сохраняемости, включая связывание (преобразование байт-кода) классов постоянного хранения, целиком возлагается на сервер Java EE. DataSource из JDBC определяется через местоположение JNDI в файле META-INF/persistence.xml. Транзакции EntityManager являются неотъемлемой частью JTA-подсистемы сервера. Spring просто использует полученную EntityManagerFactory, передавая ее объектам приложения через внедрение зависимостей и управляя транзакциями для единицы сохраняемости (обычно через JtaTransactionManager).

Если в одном приложении используется несколько единиц сохраняемости, имена бинов таких единиц сохраняемости, получаемых из JNDI, должны совпадать с именами единиц сохраняемости, которые приложение использует для ссылки на них (например, в аннотациях @PersistenceUnit и @PersistenceContext).

Использование LocalContainerEntityManagerFactoryBean

Этот вариант можно использовать для полноценного использования средств JPA в окружении приложений на базе Spring. Это подразумевает веб-контейнеры, такие как Tomcat, автономные приложения и интеграционные тесты со сложными требованиями к постоянному хранению.

Если необходимо специально сконфигурировать настройку Hibernate, то альтернативой может стать настройка собственного LocalSessionFactoryBean из Hibernate вместо обычного LocalContainerEntityManagerFactoryBean из JPA, что позволит ему взаимодействовать с кодом доступа JPA, а также с нативным кодом доступа Hibernate. Подробности см. в разделе "Нативная настройка Hibernate для взаимодействия с JPA".

LocalContainerEntityManagerFactoryBean дает полный контроль над конфигурацией EntityManagerFactory и подходит для окружений, в которых требуется тонкая настройка. LocalContainerEntityManagerFactoryBean создает экземпляр PersistenceUnitInfo на основе файла persistence.xml, предоставленной стратегии dataSourceLookup и заданного loadTimeWeaver. Таким образом, можно работать со кастомными источниками данных вне JNDI и управлять процессом привязывания. В следующем примере показано типичное определение бина для LocalContainerEntityManagerFactoryBean:

<beans>
    <bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="someDataSource"/>
        <property name="loadTimeWeaver">
            <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
        </property>
    </bean>
</beans>

В следующем примере показан типичный файл persistence.xml:

<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
    <persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL">
        <mapping-file>META-INF/orm.xml</mapping-file>
        <exclude-unlisted-classes/>
    </persistence-unit>
</persistence>
Сокращение <exclude-unlisted-classes/> указывает, что сканирование аннотированных классов сущностей не должно осуществляться. Явное значение "true" (<exclude-unlisted-classes>true</exclude-unlisted-classes/>) также означает отсутствие проверки. <exclude-unlisted-classes>false</exclude-unlisted-classes/> вызывает проверку. Однако рекомендуем опустить элемент exclude-unlisted-classes, если нужно осуществлять сканирование классов сущностей.

Использование LocalContainerEntityManagerFactoryBean является наиболее эффективным вариантом настройки JPA, обеспечивающим гибкую локальную конфигурацию в приложении. Он поддерживает ссылки на существующий DataSource из JDBC, поддерживает локальные и глобальные транзакции и так далее. Однако он также предъявляет требования к окружению выполнения, такие как наличие загрузчика классов с возможностью привязывания, если поставщику сохраняемости требуется преобразование байт-кода.

Этот вариант может конфликтовать со встроенными средствами JPA сервера Java EE. В полнофункциональном окружении Java EE рассмотрите возможность получения EntityManagerFactory из JNDI. Как вариант, задайте кастомное persistenceXmlLocation в определении LocalContainerEntityManagerFactoryBean (например, META-INF/my-persistence.xml) и включите только дескриптор с этим именем в jar-файлы вашего приложения. Поскольку сервер Java EE ищет только стандартные файлы META-INF/persistence.xml, он игнорирует такие кастомные единицы сохраняемости, что, следовательно, позволяет избежать конфликтов с настройкой JPA на основе Spring. (Это относится, например, к Resin 3.1).

Когда необходимо привязывание во время загрузки?

Не все поставщики JPA требуют наличия агента JVM. Hibernate является как раз таким примером. Если ваш поставщик не требует наличия агента или у вас имеются другие альтернативы, например, возможность применять средства, расширяющие функционал, во время сборки через кастомный компилятор или задачу на основе Ant, то не следует использовать инструмент привязывания по время загрузки.

Интерфейс LoadTimeWeaver – это класс, содержащийся в Spring, который позволяет подключать экземпляры ClassTransformer из JPA определенным образом, в зависимости от того, является ли окружение веб-контейнером или сервером приложений. Подключение ClassTransformers через agent обычно неэффективно. Агенты работают по всей виртуальной машине и проверяют каждый загружаемый класс, что обычно нежелательно в окружении производственных серверов.

Spring содержит несколько реализаций LoadTimeWeaver для различных окружений, что позволяет применять экземпляры ClassTransformer только для каждого загрузчика классов, а не для каждой виртуальной машины.

Более подробную информацию о реализаций LoadTimeWeaver и их настройке, как типизированной, так и адаптированной к различным платформам (таким как Tomcat, JBoss и WebSphere), см. в разделе, посвященному конфигурированию Spring в главе по АОП.

Как описано в разделе, посвященному конфигурации Spring, сконфигурировать LoadTimeWeaver для всего контекста можно с помощью аннотации @EnableLoadTimeWeaving или XML-элемента context:load-time-weaver. Такой глобальный инструмент привязывания автоматически подхватывается всеми экземплярами LocalContainerEntityManagerFactoryBean из JPA. В следующем примере показан предпочтительный способ настройки инструмента привязывания во время загрузки, обеспечивающий автоматическое обнаружение платформы (например, загрузчик классов Tomcat с поддержкой привязывания или агент JVM из Spring) и автоматическое распространение средства привязывания на все бины, поддерживающие инструмент привязывания:

<context:load-time-weaver/>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    ...
</bean>

Однако при необходимости можно вручную задать выделенный инструмент привязывания через свойство loadTimeWeaver, как показано в следующем примере:

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="loadTimeWeaver">
        <bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
    </property>
</bean>

Независимо от того, как настроено привязывание во время загрузки (LTW), с помощью этой техники приложения JPA, полагающиеся на инструментацию, могут выполняться на целевой платформе (например, Tomcat) без необходимости использования агента. Это особенно важно, если приложения хоста используют различные реализации JPA, поскольку преобразователи JPA применяются только на уровне класса-загрузчика и, таким образом, изолированы друг от друга.

Работа с несколькими единицами сохраняемости

Для приложений, которые используют несколько местоположений единиц сохраняемости (хранящихся, например, в различных JAR-файлах в classpath), Spring предлагает PersistenceUnitManager, который действует как центральный репозиторий и позволяет избежать процесса обнаружения единиц сохраняемости, что может быть затратным. Реализация по умолчанию позволяет задавать несколько местоположений. Эти местоположения парсится и впоследствии извлекаются через имя единицы сохраняемости. (По умолчанию в classpath выполняется поиск файлов META-INF/persistence.xml). В следующем примере сконфигурировано несколько местоположений:

<bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
    <property name="persistenceXmlLocations">
        <list>
            <value>org/springframework/orm/jpa/domain/persistence-multi.xml</value>
            <value>classpath:/my/package/**/custom-persistence.xml</value>
            <value>classpath*:META-INF/persistence.xml</value>
        </list>
    </property>
    <property name="dataSources">
        <map>
            <entry key="localDataSource" value-ref="local-db"/>
            <entry key="remoteDataSource" value-ref="remote-db"/>
        </map>
    </property>
    <!-- если источник данных не указан, используйте этот  -->
    <property name="defaultDataSource" ref="remoteDataSource"/>
</bean>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitManager" ref="pum"/>
    <property name="persistenceUnitName" value="myCustomUnit"/>
</bean>

Реализация по умолчанию позволяет настраивать экземпляры PersistenceUnitInfo (до их передачи поставщику JPA) либо декларативно (через его свойства, которые влияют на все размещаемые (hosted) единицы), либо программно (через PersistenceUnitPostProcessor, который позволяет производить выборку единиц сохраняемости). Если PersistenceUnitManager не задан, то он будет создан и использован внутри LocalContainerEntityManagerFactoryBean.

Фоновая начальная загрузка

LocalContainerEntityManagerFactoryBean поддерживает функцию фоновой начальной загрузки через свойство bootstrapExecutor, как показано в следующем примере:

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="bootstrapExecutor">
        <bean class="org.springframework.core.task.SimpleAsyncTaskExecutor"/>
    </property>
</bean>

Фактическая начальная загрузка поставщика JPA передается указанному исполнителю, а затем, параллельно, потоку начальной загрузки приложения. Открытый прокси EntityManagerFactory может быть внедрен в другие компоненты приложения и даже способен отвечать на проверку конфигурации EntityManagerFactoryInfo. Однако, если к реальному поставщику JPA обращаются другие компоненты (например, вызывая createEntityManager), эти вызовы блокируются до завершения фоновой начальной загрузки. В частности, если вы используете Spring Data JPA, не забудьте настроить отложенную начальную загрузку и для его репозиториев.

Реализация DAO на основе JPA: EntityManagerFactory и EntityManager

Хотя экземпляры EntityManagerFactory являются потокобезопасными, экземпляры EntityManager таковыми не являются. Внедренный EntityManager из JPA ведет себя как EntityManager, полученный из окружения JNDI сервера приложений, как определено спецификацией JPA. Он делегирует все вызовы текущему транзакционному EntityManager, если таковой имеется. В противном случае он возвращается к вновь созданному EntityManager для каждой операции, фактически делая его использование потокобезопасным.

Можно писать код на обычном JPA без каких-либо зависимостей Spring, используя внедренную EntityManagerFactory или EntityManager. Spring может распознавать аннотации @PersistenceUnit и @PersistenceContext как на уровне поля, так и на уровне метода, если активирован PersistenceAnnotationBeanPostProcessor. В следующем примере показана обычная реализация DAO на JPA, использующая аннотацию @PersistenceUnit:

Java
public class ProductDaoImpl implements ProductDao {
    private EntityManagerFactory emf;
    @PersistenceUnit
    public void setEntityManagerFactory(EntityManagerFactory emf) {
        this.emf = emf;
    }
    public Collection loadProductsByCategory(String category) {
        EntityManager em = this.emf.createEntityManager();
        try {
            Query query = em.createQuery("from Product as p where p.category = ?1");
            query.setParameter(1, category);
            return query.getResultList();
        }
        finally {
            if (em != null) {
                em.close();
            }
        }
    }
}
Kotlin
class ProductDaoImpl : ProductDao {
    private lateinit var emf: EntityManagerFactory
    @PersistenceUnit
    fun setEntityManagerFactory(emf: EntityManagerFactory) {
        this.emf = emf
    }
    fun loadProductsByCategory(category: String): Collection<*> {
        val em = this.emf.createEntityManager()
        val query = em.createQuery("from Product as p where p.category = ?1");
        query.setParameter(1, category);
        return query.resultList;
    }
}

Предшествующий DAO не зависит от Spring и по-прежнему хорошо вписывается в контекст приложения Spring. Более того, DAO использует преимущества аннотаций, чтобы запрашивать внедрение стандартной EntityManagerFactory, как показано в следующем примере определения бина:

<beans>
    <!-- постпроцессор бинов для JPA-аннотаций -->
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
    <bean id="myProductDao" class="product.ProductDaoImpl"/>
</beans>

В качестве альтернативы явному определению PersistenceAnnotationBeanPostProcessor, рассмотрите возможность использования XML-элемента context:annotation-config из Spring в конфигурации контекста приложения. Таким образом, все стандартные постпроцессоры Spring для конфигурации на основе аннотаций, включая CommonAnnotationBeanPostProcessor и так далее, будут автоматически регистрироваться.

Рассмотрим следующий пример:

<beans>
    <!-- постпроцессоры для всех стандартных аннотаций конфигурации -->
    <context:annotation-config/>
    <bean id="myProductDao" class="product.ProductDaoImpl"/>
</beans>

Основная проблема с таким DAO заключается в том, что он всегда создает новый EntityManager через фабрику. Можно избежать этого, запросив транзакционный EntityManager (также называемый "общим EntityManager", поскольку он является общим, потокобезопасным прокси для реального транзакционного EntityManager), который будет внедрен вместо фабрики. В следующем примере показано, как это сделать:

Java
public class ProductDaoImpl implements ProductDao {
    @PersistenceContext
    private EntityManager em;
    public Collection loadProductsByCategory(String category) {
        Query query = em.createQuery("from Product as p where p.category = :category");
        query.setParameter("category", category);
        return query.getResultList();
    }
}
Kotlin
class ProductDaoImpl : ProductDao {
    @PersistenceContext
    private lateinit var em: EntityManager
    fun loadProductsByCategory(category: String): Collection<*> {
        val query = em.createQuery("from Product as p where p.category = :category")
        query.setParameter("category", category)
        return query.resultList
    }
}

Аннотация @PersistenceContext имеет необязательный атрибут type, который по умолчанию имеет значение PersistenceContextType.TRANSACTION. Можно использовать это значение по умолчанию для получения общего прокси EntityManager. Альтернатива, а именно PersistenceContextType.EXTENDED, является совершенно другим делом. В результате получается так называемый расширенный EntityManager, который не является потокобезопасным и, следовательно, не должен использоваться в компоненте, к которому открыт одновременный доступом, такому как, например, управляемый Spring бин-одиночка. Экземпляры расширенного EntityManager предназначены для использования исключительно в компонентах, сохраняющих состояние, которые, например, содержаться в сессии, при этом жизненный цикл EntityManager не привязан к текущей транзакции, а полностью зависит от приложения.

Внедрение зависимостей на уровне метода и поля

Можно применять аннотации, обозначающие внедрение зависимостей (такие как @PersistenceUnit и @PersistenceContext) для полей или методов внутри класса – отсюда выражения "внедрение на уровне метода" и "внедрение на уровне поля". Аннотации на уровне полей лаконичны и более просты в использовании, в то время как аннотации на уровне методов позволяют дополнительно обрабатывать внедренную зависимость. В обоих случаях видимость члена (публичный, защищенный или приватный) не имеет значения.

Что же насчет аннотаций на уровне классов?

На платформе Java EE они используются для объявления зависимостей, а не для внедрения ресурсов.

Внедряемый EntityManager управляется Spring (учитывает текущую транзакцию). Даже если новая реализация DAO использует внедрение EntityManager на уровне методов вместо EntityManagerFactory, никаких изменений в XML контекста приложения не требуется благодаря использованию аннотаций.

Главное преимущество этого стиля DAO заключается в том, что он зависит только от Java Persistence API. Импорт какого-либо класса Spring не требуется. Более того, поскольку аннотации JPA распознаваемые, внедрение применяется контейнером Spring автоматически. Это привлекательно с точки зрения неагрессивности и может казаться более естественным для разработчиков JPA.

Транзакции JPA, управляемые Spring

Мы настоятельно рекомендуем ознакомиться с разделом "Декларативное управление транзакциями", если вы еще не сделали этого, чтобы получить более подробные разъяснения касательно декларативных транзакций в Spring.

Рекомендуемая стратегия для JPA – локальные транзакции с помощью встроенной поддержки транзакций JPA. JpaTransactionManager из Spring предлагает множество средств, известных по локальным транзакциям из JDBC (такие как специфичные для транзакций уровни изоляции и оптимизация режима "только для чтения" на уровне ресурсов), в отношении любого обычного пула соединений JDBC (без требований XA).

JPA через Spring также позволяет сконфигурированному JpaTransactionManager открывать транзакцию JPA для кода доступа JDBC, который обращается к тому же DataSource, при условии, что зарегистрированный JpaDialect поддерживает получение базового Connection из JDBC. Spring содержит диалекты для реализаций EclipseLink и Hibernate через JPA.

В качестве непосредственной альтернативы, нативный HibernateTransactionManager из Spring способен взаимодействовать с кодом доступа JPA, адаптируясь к некоторым особенностям Hibernate и обеспечивая взаимодействие с JDBC. Это имеет особый смысл в сочетании с настройкой LocalSessionFactoryBean. Подробнее см. в разделе "Нативная настройка Hibernate для взаимодействия с JPA".

Основные сведения о JpaDialect и JpaVendorAdapter

В качестве расширенной функции JpaTransactionManager и подклассы AbstractEntityManagerFactoryBean позволяют передавать пользовательский JpaDialect в свойство бина jpaDialect. Реализация JpaDialect может включать следующие расширенные возможности, поддерживаемые Spring, обычно в зависимости от производителя:

  • Применение специфической семантики транзакций (например, кастомного уровня изоляции или времени ожидания транзакции)

  • Получение транзакционного Connection JDBC (чтобы открыть его на DAO-объектам на основе JDBC)

  • Расширенное преобразование PersistenceExceptions в DataAccessExceptions из Spring

Это особенно полезно в случае специальной семантики транзакций и для расширенного преобразования исключений. Реализация по умолчанию(DefaultJpaDialect) не предоставляет никаких специальных возможностей, и если требуются перечисленные ранее функции, необходимо задавать соответствующий диалект.

JpaVendorAdapter, являясь еще более широким средством адаптации поставщика в первую очередь для полнофункциональной настройки LocalContainerEntityManagerFactoryBean из Spring, объединяет возможности JpaDialect с другими специфическими для поставщика вариантами по умолчанию. Задание HibernateJpaVendorAdapter или EclipseLinkJpaVendorAdapter является наиболее удобным способом автоматической настройки EntityManagerFactory для Hibernate или EclipseLink соответственно. Обратите внимание, что эти адаптеры поставщиков в первую очередь предназначены для использования при управлении транзакциями на основе Spring (то есть для использования с JpaTransactionManager).

См. javadoc по JpaDialect и JpaVendorAdapter для получения более подробной информации об их работе и о том, как они используются в рамках средств поддержки Spring для JPA.

Настройка JPA с помощью управления транзакциями через JTA

Как альтернатива JpaTransactionManager, Spring также позволяет координировать транзакции с несколькими ресурсами через JTA либо в окружении Java EE, либо с помощью отдельного координатора транзакций, такого как Atomikos. Помимо выбора JtaTransactionManager вместо JpaTransactionManager, необходимо предпринять еще несколько шагов:

  • Основные пулы соединений JDBC должны быть совместимы с XA и интегрированы с вашим координатором транзакций. Обычно в окружении Java EE это делается просто, путем открытия DataSource другого типа через JNDI. Подробности см. в документации по вашему серверу приложений. Аналогичным образом, автономный координатор транзакций обычно поставляется со специализированными вариантами DataSource, интегрированными с XA. Опять же, ознакомьтесь с документацией.

  • Настройка EntityManagerFactory из JPA должна быть сконфигурирована для JTA. Все зависит от производителя, но обычно это делается через специальные свойства, которые должны быть заданы как jpaProperties для LocalContainerEntityManagerFactoryBean. В случае Hibernate эти свойства даже зависят от версии. Подробности см. в документации по Hibernate.

  • HibernateJpaVendorAdapter из Spring применяет определенные Spring-ориентированные значения по умолчанию, такие как режим освобождения соединения, on-close, который совпадает с собственным значению по умолчанию из Hibernate в Hibernate 5.0, но уже не совпадает с ним в Hibernate 5.1+. Для настройки JTA убедитесь, что тип транзакции вашей единицы сохраняемости объявлен как "JTA". Как вариант, установите свойство hibernate.connection.handling_modeиз Hibernate 5.2 в DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT, чтобы восстановить собственное значение Hibernate по умолчанию. Соответствующие заметки см. в разделе "Ложные предупреждения сервера приложений при использовании Hibernate".

  • В качестве альтернативы, рассмотрите возможность получения EntityManagerFactory с самого сервера приложений (то есть через JNDI-поиск вместо локально объявленного LocalContainerEntityManagerFactoryBean). Предоставляемая сервером EntityManagerFactory может требовать специальных определений в конфигурации вашего сервера (что делает развертывание менее платформонезависимым), но она настроена для JTA-окружения сервера.

Нативная настройка Hibernate и нативные транзакции Hibernate для взаимодействия с JPA

Нативная настройка LocalSessionFactoryBean в сочетании с HibernateTransactionManager позволяет взаимодействовать с аннотациями @PersistenceContext и другим кодом доступа JPA. SessionFactory из Hibernate теперь нативно реализует интерфейс EntityManagerFactory из JPA, а дескриптор Session из Hibernate нативно является EntityManager для JPA. Средства поддержки JPA в Spring автоматически определяют собственные сессии Hibernate.

Поэтому такая нативная настройка Hibernate может служить заменой стандартной комбинации LocalContainerEntityManagerFactoryBean и JpaTransactionManager из JPA во многих сценариях, позволяя взаимодействовать с SessionFactory.getCurrentSession() (а также HibernateTemplate) наряду с аннотацией @PersistenceContext EntityManager в рамках одной локальной транзакции. Такая настройка также обеспечивает более тесную интеграцию с Hibernate и большую гибкость конфигурации, поскольку она не ограничена контрактами загрузочного шаблона JPA.

В таком случае конфигурация HibernateJpaVendorAdapter не нужно, поскольку встроенная в Spring настройка Hibernate предоставляет еще больше функциональных возможностей (например, кастомную настройку Hibernate Integrator, интеграцию контейнера бинов Hibernate 5.3 и более строгую оптимизация для транзакций в режиме "только для чтения"). И последнее, но не по важности: вы также можете выразить нативную настройку Hibernate через LocalSessionFactoryBuilder, с легкостью выполняя итерацию конфигурацию на основе аннотации @Bean (без использования FactoryBean).

LocalSessionFactoryBean и LocalSessionFactoryBuilder поддерживают фоновую начальную загрузку, как и LocalContainerEntityManagerFactoryBean из JPA. Вводную информацию см. в разделе "Фоновая начальная загрузка".

Для LocalSessionFactoryBean это доступно через свойство bootstrapExecutor. В программном LocalSessionFactoryBuilder перегруженный метод buildSessionFactory принимает аргумент исполнителя начальной загрузки.