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获取资源源码分析。

解析过程涉及到(补贴代码了,贴个过程):
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());
}
好的,以下是使用 Spring BootEnvironment 类和注解读取配置文件中的数据,以及使用 profile 实现环境切换的实现过程和代码: 1. 在 application.yml 配置文件中定义不同环境的配置信息: ```yml # 开发环境 spring: profiles: dev db: host: localhost port: 3306 username: root password: dev123 # 测试环境 --- spring: profiles: test db: host: localhost port: 3306 username: root password: test123 # 生产环境 --- spring: profiles: prod db: host: localhost port: 3306 username: root password: prod123 ``` 2. 在代码中使用 Environment 类和注解读取配置信息: ```java import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; @Configuration @PropertySource("classpath:application.yml") // 指定配置文件路径 public class Config { @Value("${db.host}") private String dbHost; @Value("${db.port}") private int dbPort; @Value("${db.username}") private String dbUsername; @Value("${db.password}") private String dbPassword; private final Environment environment; public Config(Environment environment) { this.environment = environment; } public void getConfig() { System.out.println("dbHost: " + dbHost); System.out.println("dbPort: " + dbPort); System.out.println("dbUsername: " + dbUsername); System.out.println("dbPassword: " + dbPassword); // 读取 profile 信息 System.out.println("Active Profiles: " + environment.getActiveProfiles()[0]); } } ``` 3. 在不同的环境中切换,可以通过在启动时指定 active profile 来实现: ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication app = new SpringApplication(Application.class); // 开发环境 app.setAdditionalProfiles("dev"); // 测试环境 // app.setAdditionalProfiles("test"); // 生产环境 // app.setAdditionalProfiles("prod"); app.run(args); } } ``` 这样,在不同的环境中启动应用时,会加载对应的配置信息,以及打印出 active profile 的信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值