Skip to content
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

Publication of DataSourceSchemaCreatedEvent is more prone to creating a cycle than it was in 2.0 #14651

Closed
cppwfs opened this issue Oct 1, 2018 · 4 comments
Labels
type: bug A general bug
Milestone

Comments

@cppwfs
Copy link

cppwfs commented Oct 1, 2018

Spring Boot 2.1.M3
Issue
We found a BeanCreationException using Spring Boot 2.1 while creating a Spring Cloud Task application that uses JPA. In our example a user has marked a method (which executes a JPARepository.save) with the @BeforeTask annotation that allows Spring Cloud Task to call this method prior to ApplicationRunner. Specifically the BeanCreationException occurs when Spring Cloud Task TaskLifecycleListener (ApplicationLifecycleListener impl) tries to resolve the Component that contains the JPARepository Autowire.

Discussion
Had a discussion with Andy Wilkinson and he validated the case.

To Reproduce

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Oct 1, 2018
@wilkinsona
Copy link
Member

There's a cycle: entityManagerFactory -> taskLifecycleListener -> taskListenerExecutor -> taskRunComponent ->taskRunRepository -> entityManagerFactory. The link from entityManagerFactory to taskLifecycleListener happens because the latter is an ApplicationListener<ApplicationEvent> and the former, via DataSourceInitializedPublisher.DataSourceSchemaCreatedPublisher (a JpaVendorAdapter), publishes an event which triggers the initialisation of taskLifecycleListener which has a transitive dependency on entityManagerFactory.

Irrespective of what, if anything, we can do about this in Boot, I think a change in Spring Cloud Task so that TaskLifecycleListener doesn't trigger early initialisation of all its dependencies as soon as an ApplicationEvent is published would be a good idea.

@wilkinsona
Copy link
Member

There's a broader problem here that affects earlier version of Spring Cloud Task. With Spring Cloud Task 1.2.3, the JPA sample will fail if there's a schema.sql file. Once again the problem is a cycle, although it's slightly different to the one described above. In this case the cycle is dataSource -> dataSourceInitializer -> taskLifecycleListener -> taskExecutionListeners -> taskListenerExecutor -> taskRunComponent -> taskRunRepository -> entityManager -> entityManagerFactory -> dataSource. The cause of the cycle is taskLifecycleListener. This time it's being created because the schema.sql script has been run, the schema created event is being published, and, therefore, application listeners are being initialised. This is a variant of #13042.

@wilkinsona
Copy link
Member

The problem can be avoided with a more focussed application listener that also makes that type information available via its bean definition:

private final class ApplicationReadyEventListener
		implements ApplicationListener<ApplicationReadyEvent> {

	@Override
	public void onApplicationEvent(ApplicationReadyEvent event) {

	}

}

@Bean
public ApplicationReadyEventListener jpaUsingApplicationListener(
		EntityManagerFactory emf) {
	return new ApplicationReadyEventListener();
}

In this case the jpaUsingApplicationListener method will only be called when an ApplicationReadyEvent is being published, not when the first ApplicationEvent is published.

@wilkinsona
Copy link
Member

wilkinsona commented Oct 2, 2018

Here's a possible change that makes Boot more tolerant of an ApplicationListener that is a potential recipient of DataSourceSchemaCreatedEvent and depends on the EntityManagerFactory. I believe it will fix the first cycle describe above but will not fix the second one or the other broader problems caused by TaskLifecycleListener described in spring-cloud/spring-cloud-task#448.

Given that Spring Cloud Task really needs to be changed in this area anyway, I don't think we have to do something here. We need to decide if we want to do something anyway. If we do, it will make things more robust for other application listeners that can trigger unwanted early initialisation.

@wilkinsona wilkinsona added for: team-attention An issue we'd like other members of the team to review type: bug A general bug and removed for: team-attention An issue we'd like other members of the team to review status: waiting-for-triage An issue we've not yet triaged labels Oct 2, 2018
@wilkinsona wilkinsona added this to the 2.1.x milestone Oct 3, 2018
@wilkinsona wilkinsona changed the title BeanCreationException when using a Component that has a JPARepository Autowired Publication of DataSourceSchemaCreatedEvent is more prone to creating a cycle than it was in 2.0 Oct 3, 2018
@wilkinsona wilkinsona modified the milestones: 2.1.x, 2.1.0.RC1 Oct 3, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

3 participants