springboot 獲取enviroment.Properties的幾種方式


springboot獲取配置資源,主要分3種方式:@Value、 @ConfigurationProperties、Enviroment對象直接調用。
前2種底層實現原理,都是通過第三種方式實現。

@Value 是spring原生功能,通過PropertyPlaceholderHelper.replacePlaceholders()方法,支持EL表達式的替換。

@ConfigurationProperties則是springboot 通過自動配置實現,並且最后通過JavaBeanBinder 來實現松綁定

獲取資源的方式

1.1、@Value標簽獲取

@Component
@Setter@Getter
public class SysValue {
    @Value("${sys.defaultPW}")
    private String defaultPW;
}

1.2、@ConfigurationProperties標簽獲取

@Component
@ConfigurationProperties(prefix = "sys")
@Setter@Getter
public class SysConfig {
    private String defaultPW;
}

1.3、直接Enviroment對象獲取回去

@Component
public class EnvironmentValue {
    @Autowired
    Environment environment;
    private String defaultPW;
    @PostConstruct//初始化調用
    public  void init(){
        defaultPW=environment.getProperty("sys.defaultPW");
    }

}

PropertyResolver初始化與方法。

2.1、api解釋:

Interface for resolving properties against any underlying source.
(解析properties針對於任何底層資源的接口)

2.2、常用實現類

PropertySourcesPropertyResolver:配置源解析器。
Environment:environment對象也繼承了解析器。

2.3、常用方法。

java.lang.String getProperty(java.lang.String key):根絕 Key獲取值。
java.lang.String resolvePlaceholders(java.lang.String text)
:替換$(....)占位符,並賦予值。(@Value 底層通過該方法實現)。

2.4、springboot中environment初始化過程初始化PropertySourcesPropertyResolver代碼。

public abstract class AbstractEnvironment implements ConfigurableEnvironment {
//初始化environment抽象類是,會初始化PropertySourcesPropertyResolver,
//並將propertySources傳入。
//獲取邏輯猜想:propertySources是一個List<>。
//getProperty方法會遍歷List根據key獲取到value
//一旦獲取到value則跳出循環,從而實現優先級問題。
private final ConfigurablePropertyResolver propertyResolver =
            new PropertySourcesPropertyResolver(this.propertySources);
}

@Value獲取資源源碼分析。

解析過程涉及到(MMP看了一晚上看不懂,補貼代碼了,貼個過程):
AutowiredAnnotationBeanPostProcessor:(@Value注解解析,賦值)

 

//賦值代碼Autowired AnnotationBeanPostProcessor.AutowiredFieldElement.inject
if (value != null) {
                ReflectionUtils.makeAccessible(field);
                field.set(bean, value);
}

PropertySourcesPlaceholderConfigurer:(通過配置資源替換表達式)
PropertySourcesPropertyResolver:(根據key獲取value。)

Enviroment 對象源碼解析。

同上第三步,直接通過PropertySourcesPropertyResolver獲取值。

2.4也能發現Enviroment new的PropertyResolver是PropertySourcesPropertyResolver

@ConfigurationProperties實現原理

核心類:
ConfigurationPropertiesBindingPostProcessor

//通過自動配置,@EnableConfigurationProperties注入
//ConfigurationPropertiesBindingPostProcessor
@Configuration
@EnableConfigurationProperties
public class ConfigurationPropertiesAutoConfiguration {

}

ConfigurationPropertiesBindingPostProcessor 類解析

//綁定數據
private void bind(Object bean, String beanName, ConfigurationProperties annotation) {
        ResolvableType type = getBeanType(bean, beanName);
        Validated validated = getAnnotation(bean, beanName, Validated.class);
        Annotation[] annotations = (validated != null)
                ? new Annotation[] { annotation, validated }
                : new Annotation[] { annotation };
        Bindable<?> target = Bindable.of(type).withExistingValue(bean)
                .withAnnotations(annotations);
        try {
            //綁定方法
            this.configurationPropertiesBinder.bind(target);
        }
        catch (Exception ex) {
            throw new ConfigurationPropertiesBindException(beanName, bean, annotation,
                    ex);
        }
}

//調用ConfigurationPropertiesBinder .bind方法。
class ConfigurationPropertiesBinder {
  public void bind(Bindable<?> target) {
        ConfigurationProperties annotation = target
                .getAnnotation(ConfigurationProperties.class);
        Assert.state(annotation != null,
                () -> "Missing @ConfigurationProperties on " + target);
        List<Validator> validators = getValidators(target);
        BindHandler bindHandler = getBindHandler(annotation, validators);
        //調用getBinder方法
        getBinder().bind(annotation.prefix(), target, bindHandler);
    }

   //getBinder方法初始化Binder對象
   // 傳入熟悉的PropertySources:也來自PropertySourcesPlaceholderConfigurer對象同@Value
   //PropertySourcesPlaceholdersResolver
   private Binder getBinder() {
        if (this.binder == null) {
            this.binder = new Binder(getConfigurationPropertySources(),
                    getPropertySourcesPlaceholdersResolver(), getConversionService(),
                    getPropertyEditorInitializer());
        }
        return this.binder;
    }
}

Binder.bind()方法解析

//很深,最后通過JavaBeanBinder 來綁定數據
//為何ConfigurationProperties無法綁定靜態對象:
//JavaBeanBinder會過濾掉靜態方法
private boolean isCandidate(Method method) {
            int modifiers = method.getModifiers();
            return Modifier.isPublic(modifiers) && !Modifier.isAbstract(modifiers)
                    && !Modifier.isStatic(modifiers)//非靜態方法
                    && !Object.class.equals(method.getDeclaringClass())
                    && !Class.class.equals(method.getDeclaringClass());
}

本文轉自:https://www.jianshu.com/p/62f0cdc435c8


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM