Skip to content

Deadlock on JPA EntityListener instantiation #22997

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
hgarus opened this issue Aug 18, 2020 · 8 comments
Closed

Deadlock on JPA EntityListener instantiation #22997

hgarus opened this issue Aug 18, 2020 · 8 comments
Labels
for: external-project For an external project and not something we can fix status: duplicate A duplicate of another issue

Comments

@hgarus
Copy link

hgarus commented Aug 18, 2020

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)
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Aug 18, 2020
@snicoll
Copy link
Member

snicoll commented Aug 18, 2020

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?

@snicoll snicoll added the status: waiting-for-feedback We need additional information before we can continue label Aug 18, 2020
@hgarus
Copy link
Author

hgarus commented Aug 18, 2020

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Aug 18, 2020
@knoobie
Copy link

knoobie commented Aug 18, 2020

Could this be related to spring-projects/spring-framework#25111?

@snicoll
Copy link
Member

snicoll commented Aug 19, 2020

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.

@snicoll snicoll closed this as completed Aug 19, 2020
@snicoll snicoll added for: external-project For an external project and not something we can fix status: duplicate A duplicate of another issue and removed status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged labels Aug 19, 2020
@steklopod

This comment has been minimized.

@dc-up42
Copy link

dc-up42 commented May 18, 2021

Have this problem on 2.4.0.

@snicoll
Copy link
Member

snicoll commented May 19, 2021

@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.

@girtsivans
Copy link

girtsivans commented Feb 4, 2022

@hgarus You can add Lazy annotation

public MyEntityListener(@Lazy DemoApplication.MyBean myBean) {
	this.myBean = myBean;
}

Found this solution here

humaolin pushed a commit to humaolin/spring-boot that referenced this issue May 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: external-project For an external project and not something we can fix status: duplicate A duplicate of another issue
Projects
None yet
Development

No branches or pull requests

7 participants