I've tried to build a minimal reproduction of the deadlock issue I mentioned in #16230, this is what I've come up with so far.
Using spring-boot-parent 2.3.3, spring-boot-starter-jpa and h2 this reliably deadlocks on startup on my machine:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.stereotype.Component;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.Id;
import javax.persistence.PrePersist;
@SpringBootApplication
@EnableJpaAuditing
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Component
public static class MyBean { }
}
@Entity
@EntityListeners({MyEntityListener.class})
class MyEntity {
@Id
private Long id;
}
class MyEntityListener {
private final DemoApplication.MyBean myBean;
// It's my understanding that constructor injection on entity listeners is supported, even though it's not
// JPA compliant. Changing this to setter Injection still results in a deadlock
public MyEntityListener(DemoApplication.MyBean myBean) {
this.myBean = myBean;
}
@PrePersist
public void prePersist(MyEntity myEntity) {
// needs to have one annotated method otherwise it's ignored
}
}
Suspending the thread with a break point (ie in AbstractEntityManagerFactoryBean.buildNativeEntityManager()
) until the main thread is waiting on the Future should always produce it.
In my actual Service I have an EntityListener with an injected dependency as well. Wrapping the dependency in an ObjectFactory seems to remove the Deadlock there as well.
Thread Dump:
"main@1" prio=5 tid=0x1 nid=NA waiting
java.lang.Thread.State: WAITING
blocks task-1@4636
at jdk.internal.misc.Unsafe.park(Unsafe.java:-1)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:211)
at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:447)
at java.util.concurrent.FutureTask.get(FutureTask.java:190)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.getNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:540)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.invokeProxyMethod(AbstractEntityManagerFactoryBean.java:497)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean$ManagedEntityManagerFactoryInvocationHandler.invoke(AbstractEntityManagerFactoryBean.java:680)
at com.sun.proxy.$Proxy55.getMetamodel(Unknown Source:-1)
at org.springframework.data.jpa.repository.config.JpaMetamodelMappingContextFactoryBean$$Lambda$424.1048842522.apply(Unknown Source:-1)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.util.Iterator.forEachRemaining(Iterator.java:133)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
at org.springframework.data.jpa.repository.config.JpaMetamodelMappingContextFactoryBean.getMetamodels(JpaMetamodelMappingContextFactoryBean.java:106)
at org.springframework.data.jpa.repository.config.JpaMetamodelMappingContextFactoryBean.createInstance(JpaMetamodelMappingContextFactoryBean.java:80)
at org.springframework.data.jpa.repository.config.JpaMetamodelMappingContextFactoryBean.createInstance(JpaMetamodelMappingContextFactoryBean.java:44)
at org.springframework.beans.factory.config.AbstractFactoryBean.afterPropertiesSet(AbstractFactoryBean.java:142)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1853)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1790)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324)
at org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$227.873827336.getObject(Unknown Source:-1)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226)
- locked <0x16d7> (a java.util.concurrent.ConcurrentHashMap)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)
at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:690)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:196)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1356)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1203)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:556)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324)
at org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$227.873827336.getObject(Unknown Source:-1)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:897)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551)
- locked <0x16d8> (a java.lang.Object)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
at com.example.demo.DemoApplication.main(DemoApplication.java:19)
"task-1@4636" prio=5 tid=0x19 nid=NA waiting for monitor entry
java.lang.Thread.State: BLOCKED
waiting for main@1 to release lock on <0x16d7> (a java.util.concurrent.ConcurrentHashMap)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:183)
at org.springframework.beans.factory.support.AbstractBeanFactory.isTypeMatch(AbstractBeanFactory.java:523)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:530)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:503)
at org.springframework.beans.factory.BeanFactoryUtils.beanNamesForTypeIncludingAncestors(BeanFactoryUtils.java:265)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1473)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1270)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1227)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:884)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:788)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:227)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1356)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1203)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:556)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:353)
at org.springframework.orm.hibernate5.SpringBeanContainer.createBean(SpringBeanContainer.java:147)
at org.springframework.orm.hibernate5.SpringBeanContainer.getBean(SpringBeanContainer.java:105)
at org.hibernate.resource.beans.internal.ManagedBeanRegistryImpl.getBean(ManagedBeanRegistryImpl.java:61)
at org.hibernate.jpa.event.internal.CallbackBuilderLegacyImpl.resolveEntityCallbacks(CallbackBuilderLegacyImpl.java:200)
at org.hibernate.jpa.event.internal.CallbackBuilderLegacyImpl.buildCallbacksForEntity(CallbackBuilderLegacyImpl.java:74)
at org.hibernate.event.service.internal.EventListenerRegistryImpl.prepare(EventListenerRegistryImpl.java:146)
at org.hibernate.boot.internal.MetadataImpl.initSessionFactory(MetadataImpl.java:379)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:213)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:469)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1259)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:391)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean$$Lambda$423.69160933.call(Unknown Source:-1)
at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
at java.util.concurrent.FutureTask.run(FutureTask.java:-1)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
at java.lang.Thread.run(Thread.java:832)
Comment From: snicoll
Thank you for the report. As I was indicated in the related issue, can you please turn that code in text into an actual project we can run?
Comment From: hgarus
@snicoll
https://github.com/hgarus/entitylistener-deadlock
Comment From: knoobie
Could this be related to https://github.com/spring-projects/spring-framework/issues/25111?
Comment From: snicoll
Sounds about right @knoobie, thank you.
@hgarus thank you for sharing a sample we can run. I'll add a note to the related issue to try out your sample once we have a fix for the framework issue.
Comment From: steklopod
Have similar issue when using gradle plugin and @AutoConfigureMockMvc
id("org.springframework.boot") version "2.3.5.RELEASE"
All @SIntegrationTest
ok, but when first @WebTest
test freeze and never ends.
But with 2.3.4.RELEASE
- no such problem
// OK
@SpringBootTest
@Target(CLASS)
@Retention(RUNTIME)
@ActiveProfiles("test")
annotation class IntegrationTest
// Freeze (deadlock)
@Target(CLASS)
@Retention(RUNTIME)
@IntegrationTest
@AutoConfigureMockMvc
annotation class WebTest
Also in this project I'm using liquibase
. No exception. Just deadlock
@WebTest
internal class UserControllerTest(@Autowired private val mockMvc: MockMvc) {
private val baseUrl = "/user"
@Test
fun userTest() {
mockMvc.perform(postWithTokenInHeader(baseUrl))
// .andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk)
}
Comment From: dc-up42
Have this problem on 2.4.0
.
Comment From: snicoll
@dc-up42 this issue is closed. If you believe you found a bug in Spring Boot, please create a separate issue. Before doing so, we'll need a small sample that reproduces the problem. You can do that by attaching a zip to the issue or sharing a link to a GitHub repository. Thank you.
Comment From: girtsivans
@hgarus You can add Lazy annotation
public MyEntityListener(@Lazy DemoApplication.MyBean myBean) {
this.myBean = myBean;
}
Found this solution here