Stop a BeanPostProcessor from preventing config of packages to scan

Previously, if a BeanPostProcessor bean was declared in a configuration
class that depended on the persistence context, packages to scan would
not be configured on the LocalContainerEntityManagerFactoryBean. This
was due to the BeanPostProcessor bean triggering the early instantiation
of the LCEMFB before EntityScanBeanPostProcessor, the BeanPostProcessor,
that applies the @EntityScan configuration, had been given a chance to
configure it.

This commit updates EntityScanBeanPostProcessor to implement Ordered
with an order of zero. This ensures that its ordering is predictable
and that it will be driven before any unordered BeanPostProcessor. This
means that, unless the user has specifically ordered their
BeanPostProcessor to run before EntityScanBeanPostProcessor, 
LCEMFB’s packages to scan will be configured as expected.

Fixes gh-2478
This commit is contained in:
Andy Wilkinson
2015-02-10 20:14:38 +00:00
parent 1035e5b029
commit b183309728
2 changed files with 44 additions and 1 deletions

View File

@@ -28,6 +28,7 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@@ -91,7 +92,7 @@ class EntityScanRegistrar implements ImportBeanDefinitionRegistrar {
* on an {@link EntityScan} annotation.
*/
static class EntityScanBeanPostProcessor implements BeanPostProcessor,
SmartInitializingSingleton {
SmartInitializingSingleton, Ordered {
private final String[] packagesToScan;
@@ -125,6 +126,11 @@ class EntityScanRegistrar implements ImportBeanDefinitionRegistrar {
+ "ensure an appropriate bean is registered.");
}
@Override
public int getOrder() {
return 0;
}
}
}

View File

@@ -22,6 +22,9 @@ import javax.persistence.PersistenceException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -99,6 +102,13 @@ public class EntityScanTests {
this.context = new AnnotationConfigApplicationContext(MissingEntityManager.class);
}
@Test
public void userDeclaredBeanPostProcessorWithEntityManagerDependencyDoesNotPreventConfigurationOfPackagesToScan() {
this.context = new AnnotationConfigApplicationContext(
BeanPostProcessorConfiguration.class, BaseConfig.class);
assertSetPackagesToScan("com.mycorp.entity");
}
private void assertSetPackagesToScan(String... expected) {
String[] actual = this.context.getBean(
TestLocalContainerEntityManagerFactoryBean.class).getPackagesToScan();
@@ -148,6 +158,33 @@ public class EntityScanTests {
static class MissingEntityManager {
}
@Configuration
@EntityScan("com.mycorp.entity")
static class BeanPostProcessorConfiguration {
@Autowired
private EntityManagerFactory entityManagerFactory;
@Bean
public BeanPostProcessor beanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
};
}
}
private static class TestLocalContainerEntityManagerFactoryBean extends
LocalContainerEntityManagerFactoryBean {