Refine validator cleanup logic
Refine the validator memory optimization so that only directly created validators are nulled out. Also update the logic to ensure that `destroy` is also called. See gh-4734
This commit is contained in:
		
							parent
							
								
									bbbe4fdcd0
								
							
						
					
					
						commit
						f3bcf94fb0
					
				| 
						 | 
				
			
			@ -90,9 +90,9 @@ public class ConfigurationPropertiesBindingPostProcessor
 | 
			
		|||
 | 
			
		||||
	private PropertySources propertySources;
 | 
			
		||||
 | 
			
		||||
	private volatile Validator validator;
 | 
			
		||||
	private Validator validator;
 | 
			
		||||
 | 
			
		||||
	private boolean ownedValidator = false;
 | 
			
		||||
	private volatile Validator localValidator;
 | 
			
		||||
 | 
			
		||||
	private ConversionService conversionService;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -195,7 +195,9 @@ public class ConfigurationPropertiesBindingPostProcessor
 | 
			
		|||
		if (this.propertySources == null) {
 | 
			
		||||
			this.propertySources = deducePropertySources();
 | 
			
		||||
		}
 | 
			
		||||
		initializeValidator();
 | 
			
		||||
		if (this.validator == null) {
 | 
			
		||||
			this.validator = getOptionalBean(VALIDATOR_BEAN_NAME, Validator.class);
 | 
			
		||||
		}
 | 
			
		||||
		if (this.conversionService == null) {
 | 
			
		||||
			this.conversionService = getOptionalBean(
 | 
			
		||||
					ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME,
 | 
			
		||||
| 
						 | 
				
			
			@ -205,36 +207,24 @@ public class ConfigurationPropertiesBindingPostProcessor
 | 
			
		|||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void onApplicationEvent(ContextRefreshedEvent event) {
 | 
			
		||||
		if (this.ownedValidator && 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()) {
 | 
			
		||||
				this.validator = new Jsr303ValidatorFactory()
 | 
			
		||||
						.run(this.applicationContext);
 | 
			
		||||
				this.ownedValidator = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private boolean isJsr303Present() {
 | 
			
		||||
		for (String validatorClass : VALIDATOR_CLASSES) {
 | 
			
		||||
			if (!ClassUtils.isPresent(validatorClass,
 | 
			
		||||
					this.applicationContext.getClassLoader())) {
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return true;
 | 
			
		||||
		freeLocalValidator();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void destroy() throws Exception {
 | 
			
		||||
		if (this.ownedValidator && this.validator != null) {
 | 
			
		||||
			((DisposableBean) this.validator).destroy();
 | 
			
		||||
		freeLocalValidator();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void freeLocalValidator() {
 | 
			
		||||
		try {
 | 
			
		||||
			Validator validator = this.localValidator;
 | 
			
		||||
			this.localValidator = null;
 | 
			
		||||
			if (validator != null) {
 | 
			
		||||
				((DisposableBean) validator).destroy();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		catch (Exception ex) {
 | 
			
		||||
			throw new IllegalStateException(ex);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -244,13 +234,11 @@ public class ConfigurationPropertiesBindingPostProcessor
 | 
			
		|||
			// Flatten the sources into a single list so they can be iterated
 | 
			
		||||
			return new FlatPropertySources(configurer.getAppliedPropertySources());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (this.environment instanceof ConfigurableEnvironment) {
 | 
			
		||||
			MutablePropertySources propertySources = ((ConfigurableEnvironment) this.environment)
 | 
			
		||||
					.getPropertySources();
 | 
			
		||||
			return new FlatPropertySources(propertySources);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// empty, so not very useful, but fulfils the contract
 | 
			
		||||
		return new MutablePropertySources();
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -353,16 +341,36 @@ public class ConfigurationPropertiesBindingPostProcessor
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	private Validator determineValidator(Object bean) {
 | 
			
		||||
		initializeValidator();
 | 
			
		||||
		boolean globalValidatorSupportBean = (this.validator != null
 | 
			
		||||
				&& this.validator.supports(bean.getClass()));
 | 
			
		||||
		Validator validator = getValidator();
 | 
			
		||||
		boolean supportsBean = (validator != null && validator.supports(bean.getClass()));
 | 
			
		||||
		if (ClassUtils.isAssignable(Validator.class, bean.getClass())) {
 | 
			
		||||
			if (!globalValidatorSupportBean) {
 | 
			
		||||
				return (Validator) bean;
 | 
			
		||||
			if (supportsBean) {
 | 
			
		||||
				return new ChainingValidator(validator, (Validator) bean);
 | 
			
		||||
			}
 | 
			
		||||
			return new ChainingValidator(this.validator, (Validator) bean);
 | 
			
		||||
			return (Validator) bean;
 | 
			
		||||
		}
 | 
			
		||||
		return (globalValidatorSupportBean ? this.validator : null);
 | 
			
		||||
		return (supportsBean ? validator : null);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private Validator getValidator() {
 | 
			
		||||
		if (this.validator != null) {
 | 
			
		||||
			return this.validator;
 | 
			
		||||
		}
 | 
			
		||||
		if (this.localValidator == null && isJsr303Present()) {
 | 
			
		||||
			this.localValidator = new LocalValidatorFactory()
 | 
			
		||||
					.run(this.applicationContext);
 | 
			
		||||
		}
 | 
			
		||||
		return this.localValidator;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private boolean isJsr303Present() {
 | 
			
		||||
		for (String validatorClass : VALIDATOR_CLASSES) {
 | 
			
		||||
			if (!ClassUtils.isPresent(validatorClass,
 | 
			
		||||
					this.applicationContext.getClassLoader())) {
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private PropertySources loadPropertySources(String[] locations,
 | 
			
		||||
| 
						 | 
				
			
			@ -408,7 +416,7 @@ public class ConfigurationPropertiesBindingPostProcessor
 | 
			
		|||
	 * Factory to create JSR 303 LocalValidatorFactoryBean. Inner class to prevent class
 | 
			
		||||
	 * loader issues.
 | 
			
		||||
	 */
 | 
			
		||||
	private static class Jsr303ValidatorFactory {
 | 
			
		||||
	private static class LocalValidatorFactory {
 | 
			
		||||
 | 
			
		||||
		public Validator run(ApplicationContext applicationContext) {
 | 
			
		||||
			LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue