From dedc6a7e9b1d4248fe38bddc471bd21398a9c979 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 7 Mar 2024 11:03:08 +0100 Subject: [PATCH] Enforce JPA/Hibernate initialization before context refresh completion Closes gh-21868 --- .../orm/hibernate5/LocalSessionFactoryBean.java | 17 +++++++++++++++-- .../jpa/AbstractEntityManagerFactoryBean.java | 14 ++++++++++++-- .../orm/jpa/hibernate/hibernate-manager.xml | 2 +- .../org/springframework/orm/jpa/inject.xml | 2 +- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java index e8c41872ee..ddf01bd7f0 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,8 +40,10 @@ import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.ResourceLoaderAware; +import org.springframework.core.InfrastructureProxy; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; @@ -79,7 +81,8 @@ import org.springframework.lang.Nullable; * @see org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean */ public class LocalSessionFactoryBean extends HibernateExceptionTranslator - implements FactoryBean, ResourceLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean { + implements FactoryBean, ResourceLoaderAware, BeanFactoryAware, + InitializingBean, SmartInitializingSingleton, DisposableBean { @Nullable private DataSource dataSource; @@ -390,6 +393,8 @@ public class LocalSessionFactoryBean extends HibernateExceptionTranslator * then block until Hibernate's bootstrapping completed, if not ready by then. * For maximum benefit, make sure to avoid early {@code SessionFactory} calls * in init methods of related beans, even for metadata introspection purposes. + *

As of 6.2, Hibernate initialization is enforced before context refresh + * completion, waiting for asynchronous bootstrapping to complete by then. * @since 4.3 * @see LocalSessionFactoryBuilder#buildSessionFactory(AsyncTaskExecutor) */ @@ -600,6 +605,14 @@ public class LocalSessionFactoryBean extends HibernateExceptionTranslator this.sessionFactory = buildSessionFactory(sfb); } + @Override + public void afterSingletonsInstantiated() { + // Enforce completion of asynchronous Hibernate initialization before context refresh completion. + if (this.sessionFactory instanceof InfrastructureProxy proxy) { + proxy.getWrappedObject(); + } + } + /** * Subclasses can override this method to perform custom initialization * of the SessionFactory instance, creating it via the given Configuration diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java b/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java index fc8f676e12..0a672639ff 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java @@ -54,6 +54,7 @@ import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.core.task.AsyncTaskExecutor; import org.springframework.dao.DataAccessException; import org.springframework.dao.support.PersistenceExceptionTranslator; @@ -90,8 +91,9 @@ import org.springframework.util.CollectionUtils; */ @SuppressWarnings("serial") public abstract class AbstractEntityManagerFactoryBean implements - FactoryBean, BeanClassLoaderAware, BeanFactoryAware, BeanNameAware, - InitializingBean, DisposableBean, EntityManagerFactoryInfo, PersistenceExceptionTranslator, Serializable { + FactoryBean, BeanClassLoaderAware, BeanFactoryAware, + BeanNameAware, InitializingBean, SmartInitializingSingleton, DisposableBean, + EntityManagerFactoryInfo, PersistenceExceptionTranslator, Serializable { /** Logger available to subclasses. */ protected final Log logger = LogFactory.getLog(getClass()); @@ -318,6 +320,8 @@ public abstract class AbstractEntityManagerFactoryBean implements * then block until the JPA provider's bootstrapping completed, if not ready by then. * For maximum benefit, make sure to avoid early {@code EntityManagerFactory} calls * in init methods of related beans, even for metadata introspection purposes. + *

As of 6.2, JPA initialization is enforced before context refresh completion, + * waiting for asynchronous bootstrapping to complete by then. * @since 4.3 */ public void setBootstrapExecutor(@Nullable AsyncTaskExecutor bootstrapExecutor) { @@ -403,6 +407,12 @@ public abstract class AbstractEntityManagerFactoryBean implements this.entityManagerFactory = createEntityManagerFactoryProxy(this.nativeEntityManagerFactory); } + @Override + public void afterSingletonsInstantiated() { + // Enforce completion of asynchronous JPA initialization before context refresh completion. + getNativeEntityManagerFactory(); + } + private EntityManagerFactory buildNativeEntityManagerFactory() { EntityManagerFactory emf; try { diff --git a/spring-orm/src/test/resources/org/springframework/orm/jpa/hibernate/hibernate-manager.xml b/spring-orm/src/test/resources/org/springframework/orm/jpa/hibernate/hibernate-manager.xml index 114d495e08..caa6265074 100644 --- a/spring-orm/src/test/resources/org/springframework/orm/jpa/hibernate/hibernate-manager.xml +++ b/spring-orm/src/test/resources/org/springframework/orm/jpa/hibernate/hibernate-manager.xml @@ -28,7 +28,7 @@ - + diff --git a/spring-orm/src/test/resources/org/springframework/orm/jpa/inject.xml b/spring-orm/src/test/resources/org/springframework/orm/jpa/inject.xml index 812ac80c45..520735843b 100644 --- a/spring-orm/src/test/resources/org/springframework/orm/jpa/inject.xml +++ b/spring-orm/src/test/resources/org/springframework/orm/jpa/inject.xml @@ -9,7 +9,7 @@ - +