Detailed explanation of propertyresourceconfigurator and its subclasses of Spring

Keywords: Spring

1, Propertyresourceconfigurator class

/*
 * Copyright 2002-2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory.config;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Properties;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.io.support.PropertiesLoaderSupport;
import org.springframework.util.ObjectUtils;

/**
 * Allows for configuration of individual bean property values from a property resource,
 * i.e. a properties file. Useful for custom config files targeted at system
 * administrators that override bean properties configured in the application context.
 *
 * <p>Two concrete implementations are provided in the distribution:
 * <ul>
 * <li>{@link PropertyOverrideConfigurer} for "beanName.property=value" style overriding
 * (<i>pushing</i> values from a properties file into bean definitions)
 * <li>{@link PropertyPlaceholderConfigurer} for replacing "${...}" placeholders
 * (<i>pulling</i> values from a properties file into bean definitions)
 * </ul>
 *
 * <p>Property values can be converted after reading them in, through overriding
 * the {@link #convertPropertyValue} method. For example, encrypted values
 * can be detected and decrypted accordingly before processing them.
 *
 * @author Juergen Hoeller
 * @since 02.10.2003
 * @see PropertyOverrideConfigurer
 * @see PropertyPlaceholderConfigurer
 */
public abstract class PropertyResourceConfigurer extends PropertiesLoaderSupport
		implements BeanFactoryPostProcessor, PriorityOrdered {

	private int order = Ordered.LOWEST_PRECEDENCE;  // default: same as non-Ordered


	/**
	 * Set the order value of this object for sorting purposes.
	 * @see PriorityOrdered
	 */
	public void setOrder(int order) {
		this.order = order;
	}

	@Override
	public int getOrder() {
		return this.order;
	}


	/**
	 * {@linkplain #mergeProperties Merge}, {@linkplain #convertProperties convert} and
	 * {@linkplain #processProperties process} properties against the given bean factory.
	 * @throws BeanInitializationException if any properties cannot be loaded
	 */
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		try {
			Properties mergedProps = mergeProperties();

			// Convert the merged properties, if necessary.
			convertProperties(mergedProps);

			// Let the subclass process the properties.
			processProperties(beanFactory, mergedProps);
		}
		catch (IOException ex) {
			throw new BeanInitializationException("Could not load properties", ex);
		}
	}

	/**
	 * Convert the given merged properties, converting property values
	 * if necessary. The result will then be processed.
	 * <p>The default implementation will invoke {@link #convertPropertyValue}
	 * for each property value, replacing the original with the converted value.
	 * @param props the Properties to convert
	 * @see #processProperties
	 */
	protected void convertProperties(Properties props) {
		Enumeration<?> propertyNames = props.propertyNames();
		while (propertyNames.hasMoreElements()) {
			String propertyName = (String) propertyNames.nextElement();
			String propertyValue = props.getProperty(propertyName);
			String convertedValue = convertProperty(propertyName, propertyValue);
			if (!ObjectUtils.nullSafeEquals(propertyValue, convertedValue)) {
				props.setProperty(propertyName, convertedValue);
			}
		}
	}

	/**
	 * Convert the given property from the properties source to the value
	 * which should be applied.
	 * <p>The default implementation calls {@link #convertPropertyValue(String)}.
	 * @param propertyName the name of the property that the value is defined for
	 * @param propertyValue the original value from the properties source
	 * @return the converted value, to be used for processing
	 * @see #convertPropertyValue(String)
	 */
	protected String convertProperty(String propertyName, String propertyValue) {
		return convertPropertyValue(propertyValue);
	}

	/**
	 * Convert the given property value from the properties source to the value
	 * which should be applied.
	 * <p>The default implementation simply returns the original value.
	 * Can be overridden in subclasses, for example to detect
	 * encrypted values and decrypt them accordingly.
	 * @param originalValue the original value from the properties source
	 * (properties file or local "properties")
	 * @return the converted value, to be used for processing
	 * @see #setProperties
	 * @see #setLocations
	 * @see #setLocation
	 * @see #convertProperty(String, String)
	 */
	protected String convertPropertyValue(String originalValue) {
		return originalValue;
	}


	/**
	 * Apply the given Properties to the given BeanFactory.
	 * @param beanFactory the BeanFactory used by the application context
	 * @param props the Properties to apply
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	protected abstract void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props)
			throws BeansException;

}

Translation notes:

Allows for configuration of individual bean property values from a property resource, i.e. a properties file. Useful for custom config files targeted at system administrators that override bean properties configured in the application context.
Allows you to configure individual bean property values from a property resource (that is, a property file). It is useful for custom configuration files for system administrators that override the bean properties configured in the application context.

Two concrete implementations are provided in the distribution:
PropertyOverrideConfigurer for "beanName.property=value" style overriding (pushing values from a properties file into bean definitions)
PropertyPlaceholderConfigurer for replacing "${...}" placeholders (pulling values from a properties file into bean definitions)
Two specific implementations are provided in the release:

PropertyOverrideConfigurer overridden by "beanName.property=value" style (push the value in the property file to the bean definition)

PropertyPlaceHolderConfigure to replace the "${...}" placeholder (pull values from the properties file into the bean definition)

Property values can be converted after reading them in, through overriding the convertPropertyValue method. For example, encrypted values can be detected and decrypted accordingly before processing them.
After reading the property value, you can convert the property value by overriding the convertPropertyValue method. For example, encrypted values can be detected and decrypted accordingly before processing them.

As can be seen from the above comments, this class mainly consists of two subclasses PropertyOverrideConfigurer and PropertyPlaceHolderConfigure, which mainly assign the properties in the configuration file to the bean s in the Spring container. The configuration information of connecting to the database, including the properties in ${} replacement properties, are implemented through this class and its subclasses. Let's look at the source code and study its implementation principle.

First, you can see that it is an abstract class that inherits the PropertiesLoaderSupport class and implements the BeanFactoryPostProcessor and PriorityOrdered interfaces.

Here, we first know that the PropertyResourceConfigurer class implements the beanfactoryprocessor class, that is, the properties in the properties are replaced before the BeanDefiniton is formed and instantiated.

It can be seen that these classes implement the sorting and priority interfaces. Therefore, its running process is to first resolve the key and value in the properties. Store it in memory, and then parse the configuration in xml , take p r o p e r t i e s solution Analysis of value , for change reach {}, replace the value parsed by properties with , replace the value parsed by properties into {}. These categories do this. Therefore, we can use this configuration when configuring database connection, and the principle comes from this.

Note: in some projects, we can see that the password of the database configuration is encrypted. Does that mean that the database password is encrypted? Not necessarily. Sometimes, in order not to let developers know the password of the database, we can encrypt the password when configuring the database, and use the PropertyResourceConfigurer class to read the information of the configuration file and decrypt it. This can meet the requirements. The PropertyResourceConfigurer class provides decryption methods, as follows:

	/**
	 * Convert the given property from the properties source to the value
	 * which should be applied.
	 * <p>The default implementation calls {@link #convertPropertyValue(String)}.
	 * @param propertyName the name of the property that the value is defined for
	 * @param propertyValue the original value from the properties source
	 * @return the converted value, to be used for processing
	 * @see #convertPropertyValue(String)
	 */
	protected String convertProperty(String propertyName, String propertyValue) {
		return convertPropertyValue(propertyValue);
	}

	/**
	 * Convert the given property value from the properties source to the value
	 * which should be applied.
	 * <p>The default implementation simply returns the original value.
	 * Can be overridden in subclasses, for example to detect
	 * encrypted values and decrypt them accordingly.
	 * @param originalValue the original value from the properties source
	 * (properties file or local "properties")
	 * @return the converted value, to be used for processing
	 * @see #setProperties
	 * @see #setLocations
	 * @see #setLocation
	 * @see #convertProperty(String, String)
	 */
	protected String convertPropertyValue(String originalValue) {
		return originalValue;
	}

Propertyresourceconfigurator is an abstract class. For the above two methods, the original value is returned. We can inherit this class, decrypt the value, and then return the uncovered value.

Posted by mpirvul on Fri, 08 Oct 2021 17:45:57 -0700