Null out validator in ContextRefreshedEvent

This is an optimization that recognizes the need for Hibernate
validator to cache reflection data, but also that we don't need it
after the bulk of the work has been done on context refresh.

Fixes gh-4734
This commit is contained in:
Dave Syer 2015-12-09 17:27:52 +00:00
parent bdc395f16e
commit e8632d9feb
2 changed files with 37 additions and 10 deletions

View File

@ -36,9 +36,11 @@ import org.springframework.boot.bind.PropertiesConfigurationFactory;
import org.springframework.boot.env.PropertySourcesLoader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
@ -71,9 +73,10 @@ import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
* @author Christian Dupuis
* @author Stephane Nicoll
*/
public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProcessor,
BeanFactoryAware, ResourceLoaderAware, EnvironmentAware, ApplicationContextAware,
InitializingBean, DisposableBean, PriorityOrdered {
public class ConfigurationPropertiesBindingPostProcessor
implements BeanPostProcessor, BeanFactoryAware, ResourceLoaderAware,
EnvironmentAware, ApplicationContextAware, InitializingBean, DisposableBean,
ApplicationListener<ContextRefreshedEvent>, PriorityOrdered {
/**
* The bean name of the configuration properties validator.
@ -87,7 +90,7 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
private PropertySources propertySources;
private Validator validator;
private volatile Validator validator;
private boolean ownedValidator = false;
@ -192,6 +195,22 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
if (this.propertySources == null) {
this.propertySources = deducePropertySources();
}
initializeValidator();
if (this.conversionService == null) {
this.conversionService = getOptionalBean(
ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME,
ConversionService.class);
}
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (this.validator != null && isJsr303Present()) {
this.validator = null; // allow it to be garbage collected
}
}
private void initializeValidator() {
if (this.validator == null) {
this.validator = getOptionalBean(VALIDATOR_BEAN_NAME, Validator.class);
if (this.validator == null && isJsr303Present()) {
@ -200,11 +219,6 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
this.ownedValidator = true;
}
}
if (this.conversionService == null) {
this.conversionService = getOptionalBean(
ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME,
ConversionService.class);
}
}
private boolean isJsr303Present() {
@ -219,7 +233,7 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
@Override
public void destroy() throws Exception {
if (this.ownedValidator) {
if (this.ownedValidator && this.validator != null) {
((DisposableBean) this.validator).destroy();
}
}
@ -339,6 +353,7 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
}
private Validator determineValidator(Object bean) {
initializeValidator();
boolean globalValidatorSupportBean = (this.validator != null
&& this.validator.supports(bean.getClass()));
if (ClassUtils.isAssignable(Validator.class, bean.getClass())) {

View File

@ -40,6 +40,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
@ -51,6 +52,7 @@ import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@ -116,6 +118,16 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
assertBindingFailure(2);
}
@Test
public void testValidationAndNullOutValidator() {
this.context = new AnnotationConfigApplicationContext();
this.context.register(TestConfiguration.class);
this.context.refresh();
ConfigurationPropertiesBindingPostProcessor bean = this.context
.getBean(ConfigurationPropertiesBindingPostProcessor.class);
assertNull(ReflectionTestUtils.getField(bean, "validator"));
}
@Test
public void testSuccessfulValidationWithJSR303() {
MockEnvironment env = new MockEnvironment();