如何解决春季环境属性中所有以"something"开头的占位符?



我有一个基于Spring Boot的Java库。就我而言,我需要以自己的方式解析以something.*开头的占位符,然后才能由某些 Spring 属性解析器解析此属性。例如:

应用程序属性

spring.datasource.url="${something.url}"

所以这个占位符与我的something.*模式相匹配,我想在春天尝试解决它之前用specific词替换它。我在哪里可以做到这一点,以便我可以避免使用 System.setProperty 创建系统属性?

以下是我实现它的尝试:

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.util.PropertyPlaceholderHelper;
import org.springframework.util.StringValueResolver;
import java.util.Properties;
public class MyPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
            throws BeansException {
        StringValueResolver valueResolver = new ReloadablePlaceholderResolvingStringValueResolver(props);
        this.doProcessProperties(beanFactoryToProcess, valueResolver);
    }
    private class ReloadablePlaceholderResolvingStringValueResolver
            implements StringValueResolver {
        private final PropertyPlaceholderHelper helper;
        private final ReloadablePropertyPlaceholderConfigurerResolver resolver;
        public ReloadablePlaceholderResolvingStringValueResolver(Properties props) {
            this.helper = new MyPropertyPlaceholderHelper(placeholderPrefix, placeholderSuffix, valueSeparator, ignoreUnresolvablePlaceholders);
            this.resolver = new ReloadablePropertyPlaceholderConfigurerResolver(props);
        }
        @Override
        public String resolveStringValue(String strVal) throws BeansException {
            String value = this.helper.replacePlaceholders(strVal, this.resolver);
            return (value.equals(nullValue) ? null : value);
        }
    }
    private class ReloadablePropertyPlaceholderConfigurerResolver
            implements PropertyPlaceholderHelper.PlaceholderResolver {
        private Properties props;
        private ReloadablePropertyPlaceholderConfigurerResolver(Properties props) {
            this.props = props;
        }
        @Override
        public String resolvePlaceholder(String placeholderName) {
            return MyPropertyPlaceholderConfigurer.this.resolvePlaceholder(placeholderName, props, SYSTEM_PROPERTIES_MODE_FALLBACK);
        }
    }
}

初始化 bean:

@Bean
public PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() {
    return new MyPropertyPlaceholderConfigurer();
}

正在解析属性:

@RestController
public class MainController {
    @Autowired
    private Environment environment;
    @GetMapping("/getEnvProeprty")
    public String getEnvironmentName() {
        return environment.getProperty("spring.datasource.url");
    }
}

我有类似的要求并解决了这个用例。

总之:

由于 spring 尝试按照 porperty 源列表中的顺序解析属性,因此基本思想是在当前Environment中 PropertySources 的顶部 [0th 索引] 添加我们的自定义属性源。

为此,请重写类PropertySourcesPlaceholderConfigurer.java中的 getAppliedPropertySources() 方法,并在当前 Spring EvnironmentaddFirst自定义属性源。因此,Spring 将首先尝试从我们的自定义源中解析占位符,如果未找到,则遍历其余的属性源。

@Configuration
public class CustomPropertySourcesPlaceholderConfigurer extends PropertySourcesPlaceholderConfigurer {
private static final String[] IGNORABLE_SECRETS = new String[] {"secrets.property1", "secrets.property2"};
@Override
public PropertySources getAppliedPropertySources() throws IllegalStateException {
    // gets the applied property sources
    MutablePropertySources appliedPropertySources = (MutablePropertySources) super.getAppliedPropertySources();
    // fetches the property source of the current evnironment
    PropertySource<?> environmentPropertySource = appliedPropertySources.get("environmentProperties");
    if (Objects.nonNull(environmentPropertySource)) {
        addCustomPropertySourceToIgnoreRefresh(environmentPropertySource);
    }
    return appliedPropertySources;
}
private void addCustomPropertySourceToIgnoreRefresh(PropertySource<?> environmentPropertySource) {
    Map<String, Object> customPropertyMap = new HashMap<>();
    
    // Iterating over properties listed in IGNORABLE_SECRETS to override them
           
    for (String ignorableSecretProperty: IGNORABLE_SECRETS) {
        customPropertyMap.put(ignorableSecretProperty, "customValueForThatPorperty");
        
        // For my use case, i'm trying to fetch the secrets from the property sources that are loaded
        // during the bootstrap phase and using them as sort of cache so that spring boot doesn't 
        // need to make grpc calls to google to resolve the secrets during the consul refresh
        //  customPropertyMap.put(ignorableSecretProperty,
        //                  environmentPropertySource.getProperty(ignorableSecretProperty));
    }
    ConfigurableEnvironment configurableEnvironment =
            (ConfigurableEnvironment) environmentPropertySource.getSource();
    // post fetching the configurable environment, adding my hash map as custom map property source
    configurableEnvironment.getPropertySources()
                           .addFirst(new MapPropertySource("customPropertySource", customPropertyMap));
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    super.postProcessBeanFactory(beanFactory);
}

}

有关更多详细信息,您可以参考我在媒体上发表的文章。

最新更新