springboot 获取enviroment.Properties的几种方式 - ppjj - 博客园

标签: | 发表时间:2020-12-25 21:54 | 作者:
出处:https://www.cnblogs.com

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

相关 [springboot enviroment properties] 推荐:

springboot获取properties文件的配置内容(转载) - Mr_伍先生 - 博客园

- -
1、使用@Value注解读取. 读取properties配置文件时,默认读取的是application.properties. //1、使用@Value注解读取. 部分放到一个单独的类A中进行读取,然后在类B中调用,则要把类A增加@Component注解,并在类B中使用@Autowired自动装配类A,代码如下.

SpringBoot-Metrics监控

- -
Metrics基本上是成熟公司里面必须做的一件事情,简单点来说就是对应用的监控,之前在一些技术不成熟的公司其实是不了解这种概念,因为业务跟技术是相关的. 当业务庞大起来,技术也会相对复杂起来,对这些复杂的系统进行监控就存在必要性了,特别是在soa化的系统中,完整一个软件的功能分布在各个系统中,针对这些功能进行监控就更必要了.

Spring 读取 properties 文件的解决方案

- - 编程语言 - ITeye博客
一、只读取单个 properties 文件. 1、在 spring 的配置文件中,加入. 2、在类中需要注入的属性实现 setter 和 getter 方法. 3、在 setter 方法前,添加 @Value 注解. propertiesName 为 properties 文件中的键. 这样,在容器启动过程中, Spring 将自动注入值.

SpringBoot的事务管理

- - ImportNew
Springboot内部提供的事务管理器是根据autoconfigure来进行决定的. 比如当使用jpa的时候,也就是pom中加入了spring-boot-starter-data-jpa这个starter之后(之前我们分析过 springboot的自动化配置原理). Springboot会构造一个JpaTransactionManager这个事务管理器.

springboot aop日志记录

- - 编程语言 - ITeye博客
一、POM增加AOP JAR包. 三、SysAspect类. 注:@annotation(cn.com.hfai.controller.system.Logweb) 一定要指定Logweb类. 四、在Controller类的方法之上加上注解 @Logweb 即可. 注:这个只是打印在控制台上,若想放到数据库中,则需要增加操作数据库的业务代码.

springboot单元测试技术

- - 海思
整个软件交付过程中,单元测试阶段是一个能够最早发现问题,并且可以重复回归问题的阶段,在单元测试阶段做的测试越充分,软件质量就越能得到保证. 具体的代码参照 示例项目 https://github.com/qihaiyan/springcamp/tree/master/spring-unit-test.

K8S部署SpringBoot应用_都超的博客-CSDN博客_k8s springboot

- -
K8S环境机器做部署用,推荐一主双从. Docker Harbor私有仓库,准备完成后在需要使用仓库的机器docker login. 开发机器需要Docker环境,build及push使用. 一、构建基本Springboot工程,本例所用版本及结构如下图. 创建测试代码,简单打印几行log. .

Maven pom.xml中的元素modules、parent、properties以及import - 青石路 - 博客园

- -
  项目中用到了maven,而且用到的内容不像. 利用maven/eclipse搭建ssm(spring+spring mvc+mybatis)用的那么简单;maven的核心是pom.xml,那么我就它来谈谈那些不同的地方;.   给我印象最深的就是如下四个元素:modules、parent、properties、import.

springboot集成shiro 实现权限控制

- - CSDN博客编程语言推荐文章
apache shiro 是一个轻量级的身份验证与授权框架,与spring security 相比较,简单易用,灵活性高,springboot本身是提供了对security的支持,毕竟是自家的东西. springboot暂时没有集成shiro,这得自己配. 本文实现从数据库读取用户信息,获取当前用户的权限或角色,通过配置文件过滤用户的角色或权限.

让SpringBoot启动更快一点

- - ImportNew
这是 2018 Spring One Platform 中的一场会议. 看完会议视频,我自己动手试了一下. 还没有观看视频的朋友推荐看一下,非常有意思. ↓我使用的是 OpenJDK 11. ❯ java --version openjdk 11.0.1 2018-10-16 OpenJDK Runtime Environment 18.9 (build 11.0.1+13) OpenJDK 64-Bit Server VM 18.9 (build 11.0.1+13, mixed mode).