Ensure unique bean definitions for EntityManager beans.

We now make sure to create unique beans to avoid autowiring resolution problems for EntityManager beans through SharedEntityManagerCreator definitions.

Closes #2699
This commit is contained in:
Mark Paluch
2022-11-14 12:00:38 +01:00
parent c5e53d5799
commit 4b1ac8a7f3
3 changed files with 52 additions and 24 deletions

View File

@@ -38,7 +38,6 @@ import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigUtils;
@@ -164,7 +163,7 @@ public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensi
super.registerBeansForRoot(registry, config);
prepareAndRegisterSharedEntityManger(registry, config);
registerSharedEntityMangerIfNotAlreadyRegistered(registry, config);
Object source = config.getSource();
@@ -208,18 +207,24 @@ public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensi
}, registry, JpaEvaluationContextExtension.class.getName(), source);
}
private String prepareAndRegisterSharedEntityManger(BeanDefinitionRegistry registry,
private String registerSharedEntityMangerIfNotAlreadyRegistered(BeanDefinitionRegistry registry,
RepositoryConfigurationSource config) {
AbstractBeanDefinition entityManager = getEntityManagerBeanDefinitionFor(config, null);
entityManager.setRole(BeanDefinition.ROLE_SUPPORT);
entityManager.setSynthetic(true);
entityManager.setPrimary(false);
entityManager.setAutowireCandidate(false);
String entityManagerBeanRef = getEntityManagerBeanRef(config);
String entityManagerBeanName = "jpaSharedEM_" + entityManagerBeanRef;
if (!registry.containsBeanDefinition(entityManagerBeanName)) {
AbstractBeanDefinition entityManager = getEntityManagerBeanDefinitionFor(config, null);
entityManager.setRole(BeanDefinition.ROLE_SUPPORT);
entityManager.setSynthetic(true);
entityManager.setPrimary(false);
entityManager.setAutowireCandidate(false);
registry.registerBeanDefinition(entityManagerBeanName, entityManager);
}
String entityManagerBeanName = BeanDefinitionReaderUtils.uniqueBeanName("jpaSharedEM", registry);
entityManagerRefs.put(config, entityManagerBeanName);
registry.registerBeanDefinition(entityManagerBeanName, entityManager);
return entityManagerBeanName;
}

View File

@@ -29,10 +29,8 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.Ordered;
import org.springframework.data.jpa.util.BeanDefinitionUtils.*;
import org.springframework.orm.jpa.SharedEntityManagerCreator;
/**
@@ -44,6 +42,7 @@ import org.springframework.orm.jpa.SharedEntityManagerCreator;
*
* @author Oliver Gierke
* @author Réda Housni Alaoui
* @author Mark Paluch
*/
public class EntityManagerBeanDefinitionRegistrarPostProcessor implements BeanFactoryPostProcessor, Ordered {
@@ -59,7 +58,7 @@ public class EntityManagerBeanDefinitionRegistrarPostProcessor implements BeanFa
return;
}
ConfigurableListableBeanFactory factory = (ConfigurableListableBeanFactory) beanFactory;
ConfigurableListableBeanFactory factory = beanFactory;
for (EntityManagerFactoryBeanDefinition definition : getEntityManagerFactoryBeanDefinitions(factory)) {
@@ -69,22 +68,27 @@ public class EntityManagerBeanDefinitionRegistrarPostProcessor implements BeanFa
continue;
}
String entityManagerBeanName = "jpaSharedEM_AWC_" + definition.getBeanName();
BeanDefinitionRegistry definitionRegistry = (BeanDefinitionRegistry) definitionFactory;
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.rootBeanDefinition("org.springframework.orm.jpa.SharedEntityManagerCreator");
builder.setFactoryMethod("createSharedEntityManager");
builder.addConstructorArgReference(definition.getBeanName());
if (!beanFactory.containsBeanDefinition(entityManagerBeanName)
&& !definitionRegistry.containsBeanDefinition(entityManagerBeanName)) {
AbstractBeanDefinition emBeanDefinition = builder.getRawBeanDefinition();
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.rootBeanDefinition("org.springframework.orm.jpa.SharedEntityManagerCreator");
builder.setFactoryMethod("createSharedEntityManager");
builder.addConstructorArgReference(definition.getBeanName());
emBeanDefinition.setPrimary(definition.getBeanDefinition().isPrimary());
emBeanDefinition.addQualifier(new AutowireCandidateQualifier(Qualifier.class, definition.getBeanName()));
emBeanDefinition.setScope(definition.getBeanDefinition().getScope());
emBeanDefinition.setSource(definition.getBeanDefinition().getSource());
emBeanDefinition.setLazyInit(true);
AbstractBeanDefinition emBeanDefinition = builder.getRawBeanDefinition();
BeanDefinitionReaderUtils.registerWithGeneratedName(emBeanDefinition, definitionRegistry);
emBeanDefinition.setPrimary(definition.getBeanDefinition().isPrimary());
emBeanDefinition.addQualifier(new AutowireCandidateQualifier(Qualifier.class, definition.getBeanName()));
emBeanDefinition.setScope(definition.getBeanDefinition().getScope());
emBeanDefinition.setSource(definition.getBeanDefinition().getSource());
emBeanDefinition.setLazyInit(true);
definitionRegistry.registerBeanDefinition(entityManagerBeanName, emBeanDefinition);
}
}
}
}

View File

@@ -33,6 +33,7 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
*
* @author Oliver Gierke
* @author Jens Schauder
* @author Mark Paluch
*/
public class EntityManagerBeanDefinitionRegistrarPostProcessorUnitTests {
@@ -65,6 +66,24 @@ public class EntityManagerBeanDefinitionRegistrarPostProcessorUnitTests {
assertThat(beanFactory.getBeanDefinitionCount()).isEqualTo(2);
}
@Test // gh-2699
void avoidsDuplicateBeanRegistrations() {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(StubEntityManagerFactoryBean.class);
builder.addConstructorArgValue(SpecialEntityManagerFactory.class);
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("factory", builder.getBeanDefinition());
beanFactory.registerBeanDefinition("jpaSharedEM_AWC_factory",
BeanDefinitionBuilder.rootBeanDefinition(Object.class).getBeanDefinition());
BeanFactoryPostProcessor processor = new EntityManagerBeanDefinitionRegistrarPostProcessor();
processor.postProcessBeanFactory(beanFactory);
assertThat(beanFactory.getBeanDefinitionCount()).isEqualTo(2);
}
interface SpecialEntityManagerFactory extends EntityManagerFactory {}
static class StubEntityManagerFactoryBean extends LocalContainerEntityManagerFactoryBean {