Skip to content

Commit dedc6a7

Browse files
committed
Enforce JPA/Hibernate initialization before context refresh completion
Closes gh-21868
1 parent c9e85ec commit dedc6a7

File tree

4 files changed

+29
-6
lines changed

4 files changed

+29
-6
lines changed

spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java

+15-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -40,8 +40,10 @@
4040
import org.springframework.beans.factory.DisposableBean;
4141
import org.springframework.beans.factory.FactoryBean;
4242
import org.springframework.beans.factory.InitializingBean;
43+
import org.springframework.beans.factory.SmartInitializingSingleton;
4344
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
4445
import org.springframework.context.ResourceLoaderAware;
46+
import org.springframework.core.InfrastructureProxy;
4547
import org.springframework.core.io.ClassPathResource;
4648
import org.springframework.core.io.Resource;
4749
import org.springframework.core.io.ResourceLoader;
@@ -79,7 +81,8 @@
7981
* @see org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
8082
*/
8183
public class LocalSessionFactoryBean extends HibernateExceptionTranslator
82-
implements FactoryBean<SessionFactory>, ResourceLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {
84+
implements FactoryBean<SessionFactory>, ResourceLoaderAware, BeanFactoryAware,
85+
InitializingBean, SmartInitializingSingleton, DisposableBean {
8386

8487
@Nullable
8588
private DataSource dataSource;
@@ -390,6 +393,8 @@ public void setPackagesToScan(String... packagesToScan) {
390393
* then block until Hibernate's bootstrapping completed, if not ready by then.
391394
* For maximum benefit, make sure to avoid early {@code SessionFactory} calls
392395
* in init methods of related beans, even for metadata introspection purposes.
396+
* <p>As of 6.2, Hibernate initialization is enforced before context refresh
397+
* completion, waiting for asynchronous bootstrapping to complete by then.
393398
* @since 4.3
394399
* @see LocalSessionFactoryBuilder#buildSessionFactory(AsyncTaskExecutor)
395400
*/
@@ -600,6 +605,14 @@ public void afterPropertiesSet() throws IOException {
600605
this.sessionFactory = buildSessionFactory(sfb);
601606
}
602607

608+
@Override
609+
public void afterSingletonsInstantiated() {
610+
// Enforce completion of asynchronous Hibernate initialization before context refresh completion.
611+
if (this.sessionFactory instanceof InfrastructureProxy proxy) {
612+
proxy.getWrappedObject();
613+
}
614+
}
615+
603616
/**
604617
* Subclasses can override this method to perform custom initialization
605618
* of the SessionFactory instance, creating it via the given Configuration

spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java

+12-2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import org.springframework.beans.factory.DisposableBean;
5555
import org.springframework.beans.factory.FactoryBean;
5656
import org.springframework.beans.factory.InitializingBean;
57+
import org.springframework.beans.factory.SmartInitializingSingleton;
5758
import org.springframework.core.task.AsyncTaskExecutor;
5859
import org.springframework.dao.DataAccessException;
5960
import org.springframework.dao.support.PersistenceExceptionTranslator;
@@ -90,8 +91,9 @@
9091
*/
9192
@SuppressWarnings("serial")
9293
public abstract class AbstractEntityManagerFactoryBean implements
93-
FactoryBean<EntityManagerFactory>, BeanClassLoaderAware, BeanFactoryAware, BeanNameAware,
94-
InitializingBean, DisposableBean, EntityManagerFactoryInfo, PersistenceExceptionTranslator, Serializable {
94+
FactoryBean<EntityManagerFactory>, BeanClassLoaderAware, BeanFactoryAware,
95+
BeanNameAware, InitializingBean, SmartInitializingSingleton, DisposableBean,
96+
EntityManagerFactoryInfo, PersistenceExceptionTranslator, Serializable {
9597

9698
/** Logger available to subclasses. */
9799
protected final Log logger = LogFactory.getLog(getClass());
@@ -318,6 +320,8 @@ public void setEntityManagerInitializer(Consumer<EntityManager> entityManagerIni
318320
* then block until the JPA provider's bootstrapping completed, if not ready by then.
319321
* For maximum benefit, make sure to avoid early {@code EntityManagerFactory} calls
320322
* in init methods of related beans, even for metadata introspection purposes.
323+
* <p>As of 6.2, JPA initialization is enforced before context refresh completion,
324+
* waiting for asynchronous bootstrapping to complete by then.
321325
* @since 4.3
322326
*/
323327
public void setBootstrapExecutor(@Nullable AsyncTaskExecutor bootstrapExecutor) {
@@ -403,6 +407,12 @@ public void afterPropertiesSet() throws PersistenceException {
403407
this.entityManagerFactory = createEntityManagerFactoryProxy(this.nativeEntityManagerFactory);
404408
}
405409

410+
@Override
411+
public void afterSingletonsInstantiated() {
412+
// Enforce completion of asynchronous JPA initialization before context refresh completion.
413+
getNativeEntityManagerFactory();
414+
}
415+
406416
private EntityManagerFactory buildNativeEntityManagerFactory() {
407417
EntityManagerFactory emf;
408418
try {

spring-orm/src/test/resources/org/springframework/orm/jpa/hibernate/hibernate-manager.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
<property name="entityManagerFactory" ref="entityManagerFactory"/>
2929
</bean>
3030

31-
<bean id="hibernateStatistics" factory-bean="entityManagerFactory" factory-method="getStatistics"/>
31+
<bean id="hibernateStatistics" factory-bean="entityManagerFactory" factory-method="getStatistics" lazy-init="true"/>
3232

3333
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
3434

spring-orm/src/test/resources/org/springframework/orm/jpa/inject.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
<bean id="dao" class="org.springframework.orm.jpa.support.PersistenceInjectionTests$DefaultPublicPersistenceUnitSetterNamedPerson"/>
1111

12-
<bean class="org.springframework.orm.jpa.support.PersistenceInjectionTests$DefaultPublicPersistenceContextSetter"/>
12+
<bean class="org.springframework.orm.jpa.support.PersistenceInjectionTests$DefaultPublicPersistenceContextSetter" lazy-init="true"/>
1313

1414
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor">
1515
<property name="proxyTargetClass" value="true"/>

0 commit comments

Comments
 (0)