springboot 获取enviroment.Properties的几种方式

springboot获取配置资源,主要分3种方式:@Value、 @ConfigurationProperties、Enviroment对象直接调用。
前2种底层实现原理,都是经过第三种方式实现。java

@Value 是spring原生功能,经过PropertyPlaceholderHelper.replacePlaceholders()方法,支持EL表达式的替换。spring

@ConfigurationProperties则是springboot 经过自动配置实现,而且最后经过JavaBeanBinder 来实现松绑定api

获取资源的方式

1.一、@Value标签获取

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

1.二、@ConfigurationProperties标签获取

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

1.三、直接Enviroment对象获取回去

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

PropertyResolver初始化与方法。

2.一、api解释:

Interface for resolving properties against any underlying source.
(解析properties针对于任何底层资源的接口)springboot

2.二、经常使用实现类

PropertySourcesPropertyResolver:配置源解析器。
Environment:environment对象也继承了解析器。源码分析

2.三、经常使用方法。

java.lang.String getProperty(java.lang.String key):根绝 Key获取值。
java.lang.String resolvePlaceholders(java.lang.String text)
:替换$(....)占位符,并赋予值。(@Value 底层经过该方法实现)。this

2.四、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注解解析,赋值)spa

 

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

PropertySourcesPlaceholderConfigurer:(经过配置资源替换表达式)
PropertySourcesPropertyResolver:(根据key获取value。)code

Enviroment 对象源码解析。

同上第三步,直接经过PropertySourcesPropertyResolver获取值。对象

2.4也能发现Enviroment new的PropertyResolver是PropertySourcesPropertyResolverblog

@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

相关文章
相关标签/搜索