• 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

  • 相关阅读:
    今年的第几天?
    特殊乘法
    abc
    求最大最小数
    二叉树遍历
    球的半径和体积
    成绩排序
    OC学习篇之---类的定义
    OC学习篇之---第一个程序HelloWorld
    OC学习篇之---类的初始化方法和点语法的使用
  • 原文地址:https://www.cnblogs.com/nizuimeiabc1/p/12173991.html
Copyright © 2020-2023  润新知