美文网首页
Spring IOC源码解析(01)PropertyResolv

Spring IOC源码解析(01)PropertyResolv

作者: juconcurrent | 来源:发表于2020-05-20 19:51 被阅读0次

前言

PropertyResolver,英文翻译为属性解析器。也就是说,我们可以通过获取属性、设置属性、替换变量等操作。

特别说明

在分析源码的过程中,我们有的时候想要方便地查看接口、类的继承关系。在Intellij IDEA中,我们可以通过以下步骤来完成。

  1. 选中需要查看的接口或类
  2. Navigate -> Type Hirerarchy
  3. 在Hirerarchy窗口中,点击Subtypes Hirerarchy
  4. 在Hirerarchy窗口中,点击Expand All
  5. 在Hirerarchy窗口中,通过快捷键Ctrl+A选中需要查看的接口或类
  6. 在Hirerarchy窗口中,鼠标右键 -> Diagrams -> Show Diagrams -> Java Class Diagrams
  7. 通过以上步骤,就能看到选中接口或类的继承关系了。

继承关系图

继承关系图

PropertyResolver源码分析

所有方法都是围绕着获取属性以及替换变量而展开的。

public interface PropertyResolver {

    /**
     * 是否包含指定属性,即获取的属性是否为null
     */
    boolean containsProperty(String key);

    /**
     * 获取属性
     */
    @Nullable
    String getProperty(String key);

    /**
     * 获取属性,当属性未获取到,或者为null时,返回默认值
     */
    String getProperty(String key, String defaultValue);

    /**
     * 获取特定类型的属性
     */
    @Nullable
    <T> T getProperty(String key, Class<T> targetType);

    /**
     * 获取特定类型的属性,当属性为获取到,或者为null时,返回默认值
     */
    <T> T getProperty(String key, Class<T> targetType, T defaultValue);

    /**
     * 获取属性,当属性未获取到,或者为null时,抛出异常
     */
    String getRequiredProperty(String key) throws IllegalStateException;

    /**
     * 获取特定类型的属性,当属性未获取到,或者为null时,抛出异常
     */
    <T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException;

    /**
     * 替换指定的文本中的变量
     */
    String resolvePlaceholders(String text);

    /**
     * 替换指定的文本中的变量,如果未替换完,则抛出异常
     */
    String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;
}

ConfigurablePropertyResolver

ConfigurablePropertyResolverPropertyResolver的基础上,增加了可配置的操作。包括:

  1. 获取或设置转换服务
  2. 设置占位符前缀
  3. 设置占位符后缀
  4. 设置属性值分隔符
  5. 其他
public interface ConfigurablePropertyResolver extends PropertyResolver {

    /**
     * 获取转换服务
     */
    ConfigurableConversionService getConversionService();

    /**
     * 设置转换服务
     */
    void setConversionService(ConfigurableConversionService conversionService);

    /**
     * 设置占位符前缀
     */
    void setPlaceholderPrefix(String placeholderPrefix);

    /**
     * 设置占位符后缀
     */
    void setPlaceholderSuffix(String placeholderSuffix);

    /**
     * 设置属性值分隔符
     */
    void setValueSeparator(@Nullable String valueSeparator);

    /**
     * 设置是否忽略未解决的变量
     * @since 3.2
     */
    void setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders);

    /**
     * 设置必须解决的变量,即:哪些变量必须要存在
     */
    void setRequiredProperties(String... requiredProperties);

    /**
     * 校验需要的变量是否存在,如果不存在,则抛出异常
     */
    void validateRequiredProperties() throws MissingRequiredPropertiesException;
}

AbstractPropertyResolver

AbstractPropertyResolver为抽象的属性解析器,其包含大部分的逻辑实现。

public abstract class AbstractPropertyResolver implements ConfigurablePropertyResolver {

    // 日志对象
    protected final Log logger = LogFactory.getLog(getClass());

    // 转换服务,字段默认为null,但是获取方法中将其设置为了DefaultConversionService
    @Nullable
    private volatile ConfigurableConversionService conversionService;

    // 非严格模式下的属性占位符辅助类
    @Nullable
    private PropertyPlaceholderHelper nonStrictHelper;

    // 严格模式下的属性占位符辅助类
    @Nullable
    private PropertyPlaceholderHelper strictHelper;
    
    // 此属性用于判断是使用严格模式,还是非严格模式
    private boolean ignoreUnresolvableNestedPlaceholders = false;
    
    // 占位符前缀。不设置的话,有默认值
    private String placeholderPrefix = SystemPropertyUtils.PLACEHOLDER_PREFIX;
    
    // 占位符后缀。不设置的话,有默认值
    private String placeholderSuffix = SystemPropertyUtils.PLACEHOLDER_SUFFIX;
    
    // 值分隔符。不设置的话,有默认值
    @Nullable
    private String valueSeparator = SystemPropertyUtils.VALUE_SEPARATOR;
    
    // 必须的属性
    private final Set<String> requiredProperties = new LinkedHashSet<>();

    @Override
    public ConfigurableConversionService getConversionService() {
        // Need to provide an independent DefaultConversionService, not the
        // shared DefaultConversionService used by PropertySourcesPropertyResolver.
        // 以懒加载的方式设置转换服务
        ConfigurableConversionService cs = this.conversionService;
        if (cs == null) {
            synchronized (this) {
                cs = this.conversionService;
                if (cs == null) {
                    cs = new DefaultConversionService();
                    this.conversionService = cs;
                }
            }
        }
        return cs;
    }

    @Override
    public void setConversionService(ConfigurableConversionService conversionService) {
        Assert.notNull(conversionService, "ConversionService must not be null");
        this.conversionService = conversionService;
    }

    /**
     * 设置占位符前缀标识符
     */
    @Override
    public void setPlaceholderPrefix(String placeholderPrefix) {
        Assert.notNull(placeholderPrefix, "'placeholderPrefix' must not be null");
        this.placeholderPrefix = placeholderPrefix;
    }

    /**
     * 设置占位符后缀标识符
     */
    @Override
    public void setPlaceholderSuffix(String placeholderSuffix) {
        Assert.notNull(placeholderSuffix, "'placeholderSuffix' must not be null");
        this.placeholderSuffix = placeholderSuffix;
    }

    /**
     * 设置值分隔符
     */
    @Override
    public void setValueSeparator(@Nullable String valueSeparator) {
        this.valueSeparator = valueSeparator;
    }

    /**
     * 设置是否忽略未解决的变量
     * @since 3.2
     */
    @Override
    public void setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders) {
        this.ignoreUnresolvableNestedPlaceholders = ignoreUnresolvableNestedPlaceholders;
    }

    /**
     * 设置必须存在的属性
     */
    @Override
    public void setRequiredProperties(String... requiredProperties) {
        Collections.addAll(this.requiredProperties, requiredProperties);
    }
    
    /**
     * 校验必须存在的属性。其内部是通过遍历的方式来实现的,只要有一个不存在,就抛出异常
     */
    @Override
    public void validateRequiredProperties() {
        MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
        for (String key : this.requiredProperties) {
            if (this.getProperty(key) == null) {
                ex.addMissingRequiredProperty(key);
            }
        }
        if (!ex.getMissingRequiredProperties().isEmpty()) {
            throw ex;
        }
    }

    /**
     * 是否包含属性。是通过属性值是否为null来判断的
     */
    @Override
    public boolean containsProperty(String key) {
        return (getProperty(key) != null);
    }

    /**
     * 获取属性
     */
    @Override
    @Nullable
    public String getProperty(String key) {
        return getProperty(key, String.class);
    }

    /**
     * 获取属性。未获取到时,返回默认值
     */
    @Override
    public String getProperty(String key, String defaultValue) {
        String value = getProperty(key);
        return (value != null ? value : defaultValue);
    }

    /**
     * 获取属性。未获取到时,返回默认值
     */
    @Override
    public <T> T getProperty(String key, Class<T> targetType, T defaultValue) {
        T value = getProperty(key, targetType);
        return (value != null ? value : defaultValue);
    }

    /**
     * 获取属性。未获取到时,抛出异常
     */
    @Override
    public String getRequiredProperty(String key) throws IllegalStateException {
        String value = getProperty(key);
        if (value == null) {
            throw new IllegalStateException("Required key '" + key + "' not found");
        }
        return value;
    }

    /**
     * 获取属性。未获取到时,抛出异常
     */
    @Override
    public <T> T getRequiredProperty(String key, Class<T> valueType) throws IllegalStateException {
        T value = getProperty(key, valueType);
        if (value == null) {
            throw new IllegalStateException("Required key '" + key + "' not found");
        }
        return value;
    }

    /**
     * 使用非严格模式的辅助类,替换变量
     */
    @Override
    public String resolvePlaceholders(String text) {
        if (this.nonStrictHelper == null) {
            this.nonStrictHelper = createPlaceholderHelper(true);
        }
        return doResolvePlaceholders(text, this.nonStrictHelper);
    }

    /**
     * 使用严格模式的辅助类,替换变量
     */
    @Override
    public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
        if (this.strictHelper == null) {
            this.strictHelper = createPlaceholderHelper(false);
        }
        return doResolvePlaceholders(text, this.strictHelper);
    }

    /**
     * 替换变量
     * @since 3.2
     * @see #setIgnoreUnresolvableNestedPlaceholders
     */
    protected String resolveNestedPlaceholders(String value) {
        return (this.ignoreUnresolvableNestedPlaceholders ?
                resolvePlaceholders(value) : resolveRequiredPlaceholders(value));
    }

    /**
     * 创建辅助类
     */
    private PropertyPlaceholderHelper createPlaceholderHelper(boolean ignoreUnresolvablePlaceholders) {
        return new PropertyPlaceholderHelper(this.placeholderPrefix, this.placeholderSuffix,
                this.valueSeparator, ignoreUnresolvablePlaceholders);
    }
    
    /**
     * 使用辅助类替换变量
     */
    private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
        return helper.replacePlaceholders(text, this::getPropertyAsRawString);
    }

    /**
     * 转换值到特定类型。当类型不匹配时需通过转换服务进行转换
     * @since 4.3.5
     */
    @SuppressWarnings("unchecked")
    @Nullable
    protected <T> T convertValueIfNecessary(Object value, @Nullable Class<T> targetType) {
        if (targetType == null) {
            return (T) value;
        }
        ConversionService conversionServiceToUse = this.conversionService;
        if (conversionServiceToUse == null) {
            // Avoid initialization of shared DefaultConversionService if
            // no standard type conversion is needed in the first place...
            if (ClassUtils.isAssignableValue(targetType, value)) {
                return (T) value;
            }
            conversionServiceToUse = DefaultConversionService.getSharedInstance();
        }
        return conversionServiceToUse.convert(value, targetType);
    }


    /**
     * 获取原始类型的属性,即:不做任何变量转换
     */
    @Nullable
    protected abstract String getPropertyAsRawString(String key);
}

PropertySourcesPropertyResolver

PropertySourcesPropertyResolver为属性解析器的最终实现,所有的操作都是围绕PropertySources来展开的,该类表示“属性源列表对象”。

public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {

    // 属性源列表对象,我们将在下一章进行分析
    @Nullable
    private final PropertySources propertySources;


    /**
     * 通过`PropertySources`进行构造
     * @param propertySources the set of {@link PropertySource} objects to use
     */
    public PropertySourcesPropertyResolver(@Nullable PropertySources propertySources) {
        this.propertySources = propertySources;
    }

    /**
     * 是否包含此属性
     */
    @Override
    public boolean containsProperty(String key) {
        if (this.propertySources != null) {
            for (PropertySource<?> propertySource : this.propertySources) {
                if (propertySource.containsProperty(key)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    @Nullable
    public String getProperty(String key) {
        return getProperty(key, String.class, true);
    }

    @Override
    @Nullable
    public <T> T getProperty(String key, Class<T> targetValueType) {
        return getProperty(key, targetValueType, true);
    }

    @Override
    @Nullable
    protected String getPropertyAsRawString(String key) {
        return getProperty(key, String.class, false);
    }

    /**
     * 获取属性,并将属性进行变量替换
     */
    @Nullable
    protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
        if (this.propertySources != null) {
            for (PropertySource<?> propertySource : this.propertySources) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Searching for key '" + key + "' in PropertySource '" +
                            propertySource.getName() + "'");
                }
                Object value = propertySource.getProperty(key);
                if (value != null) {
                    if (resolveNestedPlaceholders && value instanceof String) {
                        value = resolveNestedPlaceholders((String) value);
                    }
                    logKeyFound(key, propertySource, value);
                    return convertValueIfNecessary(value, targetValueType);
                }
            }
        }
        if (logger.isTraceEnabled()) {
            logger.trace("Could not find key '" + key + "' in any property source");
        }
        return null;
    }

    /**
     * 记录一下日志
     * @since 4.3.1
     */
    protected void logKeyFound(String key, PropertySource<?> propertySource, Object value) {
        if (logger.isDebugEnabled()) {
            logger.debug("Found key '" + key + "' in PropertySource '" + propertySource.getName() +
                    "' with value of type " + value.getClass().getSimpleName());
        }
    }
}

Environment

EnvironmentPropertyResolver的基础上,增加了对profile的支持。

public interface Environment extends PropertyResolver {

    /**
     * 获取激活的profile数组
     */
    String[] getActiveProfiles();

    /**
     * 获取默认的profile数组
     */
    String[] getDefaultProfiles();

    /**
     * 是否接受传入的profile数组
     * 当传入的profile数组中的某一个匹配上,则返回true,否则返回false
     */
    @Deprecated
    boolean acceptsProfiles(String... profiles);

    /**
     * 同上一个方法,只是类型由字符串数组变更为了Profiles对象
     */
    boolean acceptsProfiles(Profiles profiles);
}

ConfigurableEnvironment

ConfigurableEnvironmentEnvironmentConfigurablePropertyResolver的基础上,增加了对profile的修改操作。

addActiveProfile()setActiveProfiles()的区别在于,addActiveProfile()是追加,setActiveProfiles()是替换。

public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {

    /**
     * 设置激活的profile
     */
    void setActiveProfiles(String... profiles);

    /**
     * 添加激活的profile,和setActiveProfiles的区别在于,一个是追加,一个是替换。
     */
    void addActiveProfile(String profile);

    /**
     * 设置默认的profile
     */
    void setDefaultProfiles(String... profiles);

    /**
     *获取可变的属性源列表对象
     */
    MutablePropertySources getPropertySources();

    /**
     * 获取系统属性,即:System.getProperties()
     */
    Map<String, Object> getSystemProperties();

    /**
     * 获取环境属性,即:System.getEnv();
     */
    Map<String, Object> getSystemEnvironment();

    /**
     * 合并另外一个ConfigurableEnvironment到当前ConfigurableEnvironment
     */
    void merge(ConfigurableEnvironment parent);
}

AbstractEnvironment

AbstractEnvironment包含Environment几乎所有的实现。

public abstract class AbstractEnvironment implements ConfigurableEnvironment {

    /**
     * 一些常量,使用场景暂时未知。
     * @see #suppressGetenvAccess()
     */
    public static final String IGNORE_GETENV_PROPERTY_NAME = "spring.getenv.ignore";

    /**
     * 常量,表示激活的profile列表
     * @see ConfigurableEnvironment#setActiveProfiles
     */
    public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active";

    /**
     * 常量,表示默认的profile列表
     * @see ConfigurableEnvironment#setDefaultProfiles
     */
    public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profiles.default";

    /**
     * 常量,“default”
     */
    protected static final String RESERVED_DEFAULT_PROFILE_NAME = "default";

    // 日志对象
    protected final Log logger = LogFactory.getLog(getClass());

    // 激活的profile列表
    private final Set<String> activeProfiles = new LinkedHashSet<>();

    // 默认的profile列表
    private final Set<String> defaultProfiles = new LinkedHashSet<>(getReservedDefaultProfiles());

    // 可变的属性源列表
    private final MutablePropertySources propertySources = new MutablePropertySources();

    // 属性解析器,使用组合的方式来实现的
    private final ConfigurablePropertyResolver propertyResolver =
            new PropertySourcesPropertyResolver(this.propertySources);

    /**
     * 一个简单的构造器
     * @see #customizePropertySources(MutablePropertySources)
     */
    public AbstractEnvironment() {
        customizePropertySources(this.propertySources);
    }

    /**
     * 自定义属性源,这儿可通过`StandardEnvironment`的实现来看
     */
    protected void customizePropertySources(MutablePropertySources propertySources) {
    }

    /**
     * 获取默认的profile集合对象
     */
    protected Set<String> getReservedDefaultProfiles() {
        return Collections.singleton(RESERVED_DEFAULT_PROFILE_NAME);
    }


    //---------------------------------------------------------------------
    // Implementation of ConfigurableEnvironment interface
    //---------------------------------------------------------------------

    /**
     * 先获取集合对象,再转换为数组
     */
    @Override
    public String[] getActiveProfiles() {
        return StringUtils.toStringArray(doGetActiveProfiles());
    }

    /**
     * 获取激活的profile列表,如果未获取到,则说明未初始化加载。
     * 初始化加载,主要从属性源列表对象中获取。
     */
    protected Set<String> doGetActiveProfiles() {
        synchronized (this.activeProfiles) {
            if (this.activeProfiles.isEmpty()) {
                String profiles = getProperty(ACTIVE_PROFILES_PROPERTY_NAME);
                if (StringUtils.hasText(profiles)) {
                    setActiveProfiles(StringUtils.commaDelimitedListToStringArray(
                            StringUtils.trimAllWhitespace(profiles)));
                }
            }
            return this.activeProfiles;
        }
    }

    /**
     * 设置激活的profile列表,设置前需要前置校验
     * 1. profile不能为空
     * 2. 不能以叹号开头
     */
    @Override
    public void setActiveProfiles(String... profiles) {
        Assert.notNull(profiles, "Profile array must not be null");
        if (logger.isDebugEnabled()) {
            logger.debug("Activating profiles " + Arrays.asList(profiles));
        }
        synchronized (this.activeProfiles) {
            this.activeProfiles.clear();
            for (String profile : profiles) {
                validateProfile(profile);
                this.activeProfiles.add(profile);
            }
        }
    }

    /**
     * 添加激活的profile
     */
    @Override
    public void addActiveProfile(String profile) {
        if (logger.isDebugEnabled()) {
            logger.debug("Activating profile '" + profile + "'");
        }
        validateProfile(profile);
        doGetActiveProfiles();
        synchronized (this.activeProfiles) {
            this.activeProfiles.add(profile);
        }
    }

    /**
     * 获取默认的profile列表,和激活的profile操作类似
     */
    @Override
    public String[] getDefaultProfiles() {
        return StringUtils.toStringArray(doGetDefaultProfiles());
    }

    /**
     * 类似doGetActiveProfiles
     */
    protected Set<String> doGetDefaultProfiles() {
        synchronized (this.defaultProfiles) {
            if (this.defaultProfiles.equals(getReservedDefaultProfiles())) {
                String profiles = getProperty(DEFAULT_PROFILES_PROPERTY_NAME);
                if (StringUtils.hasText(profiles)) {
                    setDefaultProfiles(StringUtils.commaDelimitedListToStringArray(
                            StringUtils.trimAllWhitespace(profiles)));
                }
            }
            return this.defaultProfiles;
        }
    }

    /**
     * 类似setActiveProfiles
     */
    @Override
    public void setDefaultProfiles(String... profiles) {
        Assert.notNull(profiles, "Profile array must not be null");
        synchronized (this.defaultProfiles) {
            this.defaultProfiles.clear();
            for (String profile : profiles) {
                validateProfile(profile);
                this.defaultProfiles.add(profile);
            }
        }
    }

    /**
     * 判断profile是否匹配,只要有一个匹配即返回true。
     * 特别注意:叹号表示“非”
     */
    @Override
    @Deprecated
    public boolean acceptsProfiles(String... profiles) {
        Assert.notEmpty(profiles, "Must specify at least one profile");
        for (String profile : profiles) {
            if (StringUtils.hasLength(profile) && profile.charAt(0) == '!') {
                if (!isProfileActive(profile.substring(1))) {
                    return true;
                }
            }
            else if (isProfileActive(profile)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 使用Profiles类的函数式匹配方式替换for遍历的方式
     */
    @Override
    public boolean acceptsProfiles(Profiles profiles) {
        Assert.notNull(profiles, "Profiles must not be null");
        return profiles.matches(this::isProfileActive);
    }

    /**
     * 当前profile是否在激活的profile列表中
     */
    protected boolean isProfileActive(String profile) {
        validateProfile(profile);
        Set<String> currentActiveProfiles = doGetActiveProfiles();
        return (currentActiveProfiles.contains(profile) ||
                (currentActiveProfiles.isEmpty() && doGetDefaultProfiles().contains(profile)));
    }

    /**
     * 校验profile,包括空和叹号
     */
    protected void validateProfile(String profile) {
        if (!StringUtils.hasText(profile)) {
            throw new IllegalArgumentException("Invalid profile [" + profile + "]: must contain text");
        }
        if (profile.charAt(0) == '!') {
            throw new IllegalArgumentException("Invalid profile [" + profile + "]: must not begin with ! operator");
        }
    }

    /**
     * 获取可变的属性源列表对象
     */
    @Override
    public MutablePropertySources getPropertySources() {
        return this.propertySources;
    }

    /**
     * 获取系统属性,优先从System.getProperties()获取;
     * 获取不到的话,再通过懒加载的方式,从System.getProperty(attributeName)获取。
     */
    @Override
    @SuppressWarnings({"rawtypes", "unchecked"})
    public Map<String, Object> getSystemProperties() {
        try {
            return (Map) System.getProperties();
        }
        catch (AccessControlException ex) {
            return (Map) new ReadOnlySystemAttributesMap() {
                @Override
                @Nullable
                protected String getSystemAttribute(String attributeName) {
                    try {
                        return System.getProperty(attributeName);
                    }
                    catch (AccessControlException ex) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Caught AccessControlException when accessing system property '" +
                                    attributeName + "'; its value will be returned [null]. Reason: " + ex.getMessage());
                        }
                        return null;
                    }
                }
            };
        }
    }

    /**
     * 获取环境属性,优先从System.getenv()获取;
     * 获取不到的话,再通过懒加载的方式,从System.getenv(attributeName)获取。
     */
    @Override
    @SuppressWarnings({"rawtypes", "unchecked"})
    public Map<String, Object> getSystemEnvironment() {
        if (suppressGetenvAccess()) {
            return Collections.emptyMap();
        }
        try {
            return (Map) System.getenv();
        }
        catch (AccessControlException ex) {
            return (Map) new ReadOnlySystemAttributesMap() {
                @Override
                @Nullable
                protected String getSystemAttribute(String attributeName) {
                    try {
                        return System.getenv(attributeName);
                    }
                    catch (AccessControlException ex) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Caught AccessControlException when accessing system environment variable '" +
                                    attributeName + "'; its value will be returned [null]. Reason: " + ex.getMessage());
                        }
                        return null;
                    }
                }
            };
        }
    }

    /**
     * 通过spring.properties,获取参数
     */
    protected boolean suppressGetenvAccess() {
        return SpringProperties.getFlag(IGNORE_GETENV_PROPERTY_NAME);
    }

    /**
     * 合并操作。主要合并以下属性:
     * 1. propertySources
     * 2. activeProfiles
     * 3. defaultProfiles
     */
    @Override
    public void merge(ConfigurableEnvironment parent) {
        for (PropertySource<?> ps : parent.getPropertySources()) {
            if (!this.propertySources.contains(ps.getName())) {
                this.propertySources.addLast(ps);
            }
        }
        String[] parentActiveProfiles = parent.getActiveProfiles();
        if (!ObjectUtils.isEmpty(parentActiveProfiles)) {
            synchronized (this.activeProfiles) {
                Collections.addAll(this.activeProfiles, parentActiveProfiles);
            }
        }
        String[] parentDefaultProfiles = parent.getDefaultProfiles();
        if (!ObjectUtils.isEmpty(parentDefaultProfiles)) {
            synchronized (this.defaultProfiles) {
                this.defaultProfiles.remove(RESERVED_DEFAULT_PROFILE_NAME);
                Collections.addAll(this.defaultProfiles, parentDefaultProfiles);
            }
        }
    }


    //---------------------------------------------------------------------
    // Implementation of ConfigurablePropertyResolver interface
    //---------------------------------------------------------------------

    @Override
    public ConfigurableConversionService getConversionService() {
        return this.propertyResolver.getConversionService();
    }

    @Override
    public void setConversionService(ConfigurableConversionService conversionService) {
        this.propertyResolver.setConversionService(conversionService);
    }

    @Override
    public void setPlaceholderPrefix(String placeholderPrefix) {
        this.propertyResolver.setPlaceholderPrefix(placeholderPrefix);
    }

    @Override
    public void setPlaceholderSuffix(String placeholderSuffix) {
        this.propertyResolver.setPlaceholderSuffix(placeholderSuffix);
    }

    @Override
    public void setValueSeparator(@Nullable String valueSeparator) {
        this.propertyResolver.setValueSeparator(valueSeparator);
    }

    @Override
    public void setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders) {
        this.propertyResolver.setIgnoreUnresolvableNestedPlaceholders(ignoreUnresolvableNestedPlaceholders);
    }

    @Override
    public void setRequiredProperties(String... requiredProperties) {
        this.propertyResolver.setRequiredProperties(requiredProperties);
    }

    @Override
    public void validateRequiredProperties() throws MissingRequiredPropertiesException {
        this.propertyResolver.validateRequiredProperties();
    }


    //---------------------------------------------------------------------
    // Implementation of PropertyResolver interface
    //---------------------------------------------------------------------

    @Override
    public boolean containsProperty(String key) {
        return this.propertyResolver.containsProperty(key);
    }

    @Override
    @Nullable
    public String getProperty(String key) {
        return this.propertyResolver.getProperty(key);
    }

    @Override
    public String getProperty(String key, String defaultValue) {
        return this.propertyResolver.getProperty(key, defaultValue);
    }

    @Override
    @Nullable
    public <T> T getProperty(String key, Class<T> targetType) {
        return this.propertyResolver.getProperty(key, targetType);
    }

    @Override
    public <T> T getProperty(String key, Class<T> targetType, T defaultValue) {
        return this.propertyResolver.getProperty(key, targetType, defaultValue);
    }

    @Override
    public String getRequiredProperty(String key) throws IllegalStateException {
        return this.propertyResolver.getRequiredProperty(key);
    }

    @Override
    public <T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException {
        return this.propertyResolver.getRequiredProperty(key, targetType);
    }

    @Override
    public String resolvePlaceholders(String text) {
        return this.propertyResolver.resolvePlaceholders(text);
    }

    @Override
    public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
        return this.propertyResolver.resolveRequiredPlaceholders(text);
    }


    @Override
    public String toString() {
        return getClass().getSimpleName() + " {activeProfiles=" + this.activeProfiles +
                ", defaultProfiles=" + this.defaultProfiles + ", propertySources=" + this.propertySources + "}";
    }
}

StandardEnvironment

StandardEnvironment主要扩展了系统属性和环境属性。

public class StandardEnvironment extends AbstractEnvironment {

    /** System environment property source name: {@value}. */
    public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";

    /** JVM system properties property source name: {@value}. */
    public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";


    /**
     * 优先从System.getProperties()获取。
     * 获取不到,再从System.getEnv()获取。
     */
    @Override
    protected void customizePropertySources(MutablePropertySources propertySources) {
        propertySources.addLast(
                new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
        propertySources.addLast(
                new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
    }
}

PropertyPlaceholderHelper

PropertyPlaceholderHelper,属性占位符辅助类,是最终完成变量替换的地方。

真正替换占位符变量的方法,包含以下3个重要特性:

  1. 通过递归+遍历的方式,解决变量循环引用的问题,如:{{var}Name}
  2. 通过Set集合的方式,避免变量循环引用的问题
  3. 通过值分隔符,在变量替换失败的情况下,返回默认值

同时,我们引申出了函数接口的两个好处:

  1. 提高方法复用程度
  2. 简化编码难度
public class PropertyPlaceholderHelper {

    // 日志对象
    private static final Log logger = LogFactory.getLog(PropertyPlaceholderHelper.class);

    private static final Map<String, String> wellKnownSimplePrefixes = new HashMap<>(4);

    static {
        wellKnownSimplePrefixes.put("}", "{");
        wellKnownSimplePrefixes.put("]", "[");
        wellKnownSimplePrefixes.put(")", "(");
    }

    // 占位符前缀
    private final String placeholderPrefix;

    // 占位符后缀
    private final String placeholderSuffix;

    private final String simplePrefix;

    // 值分隔符,分隔符前为变量名,分隔符后为默认值
    @Nullable
    private final String valueSeparator;

    // 是否忽略未解决的占位符变量
    private final boolean ignoreUnresolvablePlaceholders;


    /**
     * 通过指定的占位符前缀和后缀创建辅助类
     */
    public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix) {
        this(placeholderPrefix, placeholderSuffix, null, true);
    }

    /**
     * 全量参数创建辅助类
     */
    public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix,
            @Nullable String valueSeparator, boolean ignoreUnresolvablePlaceholders) {

        Assert.notNull(placeholderPrefix, "'placeholderPrefix' must not be null");
        Assert.notNull(placeholderSuffix, "'placeholderSuffix' must not be null");
        this.placeholderPrefix = placeholderPrefix;
        this.placeholderSuffix = placeholderSuffix;
        String simplePrefixForSuffix = wellKnownSimplePrefixes.get(this.placeholderSuffix);
        if (simplePrefixForSuffix != null && this.placeholderPrefix.endsWith(simplePrefixForSuffix)) {
            this.simplePrefix = simplePrefixForSuffix;
        }
        else {
            this.simplePrefix = this.placeholderPrefix;
        }
        this.valueSeparator = valueSeparator;
        this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
    }


    /**
     * 通过变量列表,替换文本的占位符变量
     */
    public String replacePlaceholders(String value, final Properties properties) {
        Assert.notNull(properties, "'properties' must not be null");
        return replacePlaceholders(value, properties::getProperty);
    }

    /**
     * 替换占位符变量
     */
    public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
        Assert.notNull(value, "'value' must not be null");
        return parseStringValue(value, placeholderResolver, new HashSet<>());
    }

    /**
     * 真正替换占位符变量的方法
     * 1. 通过递归+遍历的方式,解决变量循环引用的问题,如:${${var}Name}
     * 2. 通过Set集合的方式,避免变量循环引用的问题
     * 3. 通过值分隔符,在变量替换失败的情况下,返回默认值
     */
    protected String parseStringValue(
            String value, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {

        StringBuilder result = new StringBuilder(value);

        int startIndex = value.indexOf(this.placeholderPrefix);
        while (startIndex != -1) {
            int endIndex = findPlaceholderEndIndex(result, startIndex);
            if (endIndex != -1) {
                String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
                String originalPlaceholder = placeholder;
                if (!visitedPlaceholders.add(originalPlaceholder)) {
                    throw new IllegalArgumentException(
                            "Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
                }
                // Recursive invocation, parsing placeholders contained in the placeholder key.
                placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
                // Now obtain the value for the fully resolved key...
                String propVal = placeholderResolver.resolvePlaceholder(placeholder);
                if (propVal == null && this.valueSeparator != null) {
                    int separatorIndex = placeholder.indexOf(this.valueSeparator);
                    if (separatorIndex != -1) {
                        String actualPlaceholder = placeholder.substring(0, separatorIndex);
                        String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
                        propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
                        if (propVal == null) {
                            propVal = defaultValue;
                        }
                    }
                }
                if (propVal != null) {
                    // Recursive invocation, parsing placeholders contained in the
                    // previously resolved placeholder value.
                    propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
                    result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
                    if (logger.isTraceEnabled()) {
                        logger.trace("Resolved placeholder '" + placeholder + "'");
                    }
                    startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
                }
                else if (this.ignoreUnresolvablePlaceholders) {
                    // Proceed with unprocessed value.
                    startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
                }
                else {
                    throw new IllegalArgumentException("Could not resolve placeholder '" +
                            placeholder + "'" + " in value \"" + value + "\"");
                }
                visitedPlaceholders.remove(originalPlaceholder);
            }
            else {
                startIndex = -1;
            }
        }

        return result.toString();
    }

    private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
        int index = startIndex + this.placeholderPrefix.length();
        int withinNestedPlaceholder = 0;
        while (index < buf.length()) {
            if (StringUtils.substringMatch(buf, index, this.placeholderSuffix)) {
                if (withinNestedPlaceholder > 0) {
                    withinNestedPlaceholder--;
                    index = index + this.placeholderSuffix.length();
                }
                else {
                    return index;
                }
            }
            else if (StringUtils.substringMatch(buf, index, this.simplePrefix)) {
                withinNestedPlaceholder++;
                index = index + this.simplePrefix.length();
            }
            else {
                index++;
            }
        }
        return -1;
    }


    /**
     * 函数接口,有两个好处:
     * 1. 提高方法复用程度
     * 2. 简化编码难度
     * Strategy interface used to resolve replacement values for placeholders contained in Strings.
     */
    @FunctionalInterface
    public interface PlaceholderResolver {

        /**
         * Resolve the supplied placeholder name to the replacement value.
         * @param placeholderName the name of the placeholder to resolve
         * @return the replacement value, or {@code null} if no replacement is to be made
         */
        @Nullable
        String resolvePlaceholder(String placeholderName);
    }
}

总结

属性解析器,主要功能是通过属性源列表对象,读取或获取属性。同时可根据这些属性,对文本中的变量进行替换操作。

属性解析器中最至关重要的是Environment,其包含了对profile的操作。例如:

  1. 设置profile
  2. 获取profile
  3. profile是否满足

profile,就是环境的代名词。在互联网企业中,环境是很重要的,大体上,我们可以将环境拆分为开发环境、测试环境、灰度环境和线上环境。

profile又分为激活的profile和默认的profile。为啥会有这两个呢?主要是考虑到在未获取到激活的profile时,我们还可以通过默认的profile来操作。这种兼容性在mock环境和单元测试环境下特别有用。

相关文章

网友评论

      本文标题:Spring IOC源码解析(01)PropertyResolv

      本文链接:https://www.haomeiwen.com/subject/jtfoohtx.html