详解PropertyPlaceholderConfigurer、PropertyOverrideConfigurer等对属性配置文件Properties的加载和使用【享学Spring】(下)

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 详解PropertyPlaceholderConfigurer、PropertyOverrideConfigurer等对属性配置文件Properties的加载和使用【享学Spring】(下)

溜个例子:


@Configuration
public class RootConfig {
    @Bean
    public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
        configurer.setOrder(Ordered.HIGHEST_PRECEDENCE);
        configurer.setLocation(new ClassPathResource("beaninfo.properties"));
        return configurer;
    }
    @Scope("${bean.scope}") // 这里是能够使用占位符的
    @Bean
    public Person person() {
        Person person = new Person();
        return person;
    }
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {RootConfig.class})
public class TestSpringBean {
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private ConfigurableBeanFactory beanFactory;
    // 通过它,可以把生效的配置都拿到
    @Autowired
    private PropertySourcesPlaceholderConfigurer configurer;
    @Test
    public void test1() {
        Environment environment = applicationContext.getEnvironment();
        BeanExpressionResolver beanExpressionResolver = beanFactory.getBeanExpressionResolver();
        PropertySources appliedPropertySources = configurer.getAppliedPropertySources();
        System.out.println(environment.containsProperty("bean.scope")); //false  注意环境里是没有这个key的
        System.out.println(beanExpressionResolver);
        System.out.println(appliedPropertySources);
        // 获取环境的和我们自己导入的
        PropertySource<?> envProperties = appliedPropertySources.get(PropertySourcesPlaceholderConfigurer.ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME);
        PropertySource<?> localProperties = appliedPropertySources.get(PropertySourcesPlaceholderConfigurer.LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME);
        System.out.println(envProperties.getSource() == environment); //true  可以看到这个envProperties的source和环境里的是同一个
        System.out.println(localProperties.containsProperty("bean.scope"));//true 本地配置里是包含这个属性的
    }
}


从上面测试结果可知,PropertySourcesPlaceholderConfigurer是一种更加强大的加载配置文件处理占位符的工具。在Spring3.1之后建议使用它来加载配置文件进来,这样我们若运行时真有需要的话也是可以访问的。


思考题:竟然Properties属性最终都不会放进Environment环境抽象里,那为何@Value这个注解能够通过占位符访问到呢?


因为这篇博文:【小家Spring】Spring中@Value注解有多强大?从原理层面去剖析为何它有如此大的“能耐“ 详细讲解了@Value这个注解,所以这个思考题有兴趣的小伙伴可以结合本文思考一番~

PropertyOverrideConfigurer


它是抽象类PropertyResourceConfigurer的子类,它和PlaceholderConfigurerSupport平级。


PropertyOverrideConfigurer类似于PropertyPlaceholderConfigurer,与PropertyPlaceholderConfigurer 不同的是: PropertyOverrideConfigurer 利用属性文件的相关信息,覆盖XML 配置文件中定义。即PropertyOverrideConfigurer允许XML 配置文件中有默认的配置信息。


如果PropertyOverrideConfigurer 的属性文件有对应配置信息,则XML 文件中的配

置信息被覆盖:否则,直接使用XML 文件中的配置信息。

// @since 12.03.2003
public class PropertyOverrideConfigurer extends PropertyResourceConfigurer {
  // The default bean name separator.  
  public static final String DEFAULT_BEAN_NAME_SEPARATOR = ".";
  // 下面提供了set方法可以修改
  private String beanNameSeparator = DEFAULT_BEAN_NAME_SEPARATOR;
  private boolean ignoreInvalidKeys = false; // 默认是不忽略非法的key
  private final Set<String> beanNames = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
  // 实现了父类的抽象方法:给每个bean进行覆盖处理   注意:这里不是处理占位符~~~~
  @Override
  protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props)
      throws BeansException {
    // 按照props有的这些属性值们进行覆盖~~~~
    for (Enumeration<?> names = props.propertyNames(); names.hasMoreElements();) {
      String key = (String) names.nextElement();
      try {
        // 1、拿到beanName 这样拿出来String beanName = key.substring(0, separatorIndex);
        // 2、根据beanName拿到bean定义信息BeanDefinition
        // 3、bdToUse.getPropertyValues().addPropertyValue(pv);  显然这样子存在的key就覆盖  否则保持原样
        processKey(beanFactory, key, props.getProperty(key));
      }
    }
  }
}


需要注意的是Properties属性文件:


beanName.property=value  //第一个.前面一定是beanName


请保证这个beanName一定存在。它会根据beanName找到这个bean,然后override这个bean的相关属性值的。


因为这个类使用得相对较少,但使用步骤基本同上,因此此处就不再叙述了


关于Spring下和SpringBoot下属性配置文件使用${}占位符的说明


比如有这个属性文件;

# 故意把它放在第一位 最顶部
app.full=${app.key} + ${app.myname}
app.myname=fsx
app.key=${user.home}


在Spring环境下测试使用:


@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {RootConfig.class, JdbcConfig.class})
public class TestSpringBean {
    @Value("${app.full}")
    private String key;
    @Test
    public void test1() throws SQLException {
        System.out.println(key); //C:\Users\fangshixiang + fsx
    }
}


可以看到在Spring环境下,Properties属性文件是能够使用占位符和直接读取环境中的值的。并且亲测发现不管是使用@PropertySource还是使用配置Bean PropertySourcesPlaceholderConfigurer的方式加载进来,都是能够正常work的。


至于它的原理,为何支持占位符的解析呢?其实上面都说了,此处不再说明了


关于SpringBoot下,就更不用说了。它的application.properties等配置文件里更是能够世界使用占位符和读取环境变量(系统属性值)的。


有个小细节一定要注意:它作为一个PropertySource存在的时候永远是原样。

image.png


真正解析占位符是取出来以后:


image.png


具体参考类:PropertySourcesPropertyResolver#getProperty方法~ 由它解析这些占位符。可以想到,最终都是委托给PropertyPlaceholderHelper去解析的~~~~

总结


从上面的分析可以看出,PropertyResourceConfigurer自身主要是抽象了对容器中所有bean定义的属性进行处理的一般逻辑,实现在接口BeanFactoryPostProcessor所定义的方法postProcessBeanFactory中。


这样容器启动时,bean容器的后置处理阶段,所有bean定义的属性都会被当前configure进行处理,处理时所使用的属性来源自当前configure基类PropertiesLoaderSupport所约定的那些属性,至于做什么样的处理,由当前configure的具体实现类,也就是PropertyResourceConfigurer的实现子类自己提供实现。

相关文章
|
2月前
|
XML Java 数据格式
Spring从入门到入土(xml配置文件的基础使用方式)
本文详细介绍了Spring框架中XML配置文件的使用方法,包括读取配置文件、创建带参数的构造对象、使用工厂方法和静态方法创建对象、对象生命周期管理以及单例和多例模式的测试。
119 7
Spring从入门到入土(xml配置文件的基础使用方式)
|
2月前
|
Java API Spring
在 Spring 配置文件中配置 Filter 的步骤
【10月更文挑战第21天】在 Spring 配置文件中配置 Filter 是实现请求过滤的重要手段。通过合理的配置,可以灵活地对请求进行处理,满足各种应用需求。还可以根据具体的项目要求和实际情况,进一步深入研究和优化 Filter 的配置,以提高应用的性能和安全性。
|
21天前
|
监控 IDE Java
如何在无需重新启动服务器的情况下在 Spring Boot 上重新加载我的更改?
如何在无需重新启动服务器的情况下在 Spring Boot 上重新加载我的更改?
41 8
|
3月前
|
缓存 安全 Java
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
从底层源码入手,通过代码示例,追踪AnnotationConfigApplicationContext加载配置类、启动Spring容器的整个流程,并对IOC、BeanDefinition、PostProcesser等相关概念进行解释
305 24
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
|
2月前
|
Java 测试技术 Spring
springboot学习三:Spring Boot 配置文件语法、静态工具类读取配置文件、静态工具类读取配置文件
这篇文章介绍了Spring Boot中配置文件的语法、如何读取配置文件以及如何通过静态工具类读取配置文件。
132 0
springboot学习三:Spring Boot 配置文件语法、静态工具类读取配置文件、静态工具类读取配置文件
|
3月前
|
XML 存储 Java
spring源码刨析-spring-beans(内部核心组件,beanDefinition加载过程)
spring源码刨析-spring-beans(内部核心组件,beanDefinition加载过程)
|
3月前
|
消息中间件 NoSQL 安全
(转)Spring Boot加载 不同位置的 application.properties配置文件顺序规则
这篇文章介绍了Spring Boot加载配置文件的顺序规则,包括不同位置的application.properties文件的加载优先级,以及如何通过命令行参数或环境变量来指定配置文件的名称和位置。
|
4月前
|
Java Spring 传感器
AI 浪潮席卷,Spring 框架配置文件管理与环境感知,为软件稳定护航,你还在等什么?
【8月更文挑战第31天】在软件开发中,配置文件管理至关重要。Spring框架提供强大支持,便于应对不同环境需求,如电商项目的开发、测试与生产环境。它支持多种格式的配置文件(如properties和YAML),并能根据环境加载不同配置,如数据库连接信息。通过`@Profile`注解可指定特定环境下的配置生效,同时支持通过命令行参数或环境变量覆盖配置值,确保应用稳定性和可靠性。
66 0
|
4月前
|
Java Spring 开发者
Spring 框架配置属性绑定大比拼:@Value 与 @ConfigurationProperties,谁才是真正的王者?
【8月更文挑战第31天】Spring 框架提供 `@Value` 和 `@ConfigurationProperties` 两种配置属性绑定方式。`@Value` 简单直接,适用于简单场景,但处理复杂配置时略显不足。`@ConfigurationProperties` 则以类级别绑定配置,简化代码并更好组织配置信息。本文通过示例对比两者特点,帮助开发者根据具体需求选择合适的绑定方式,实现高效且易维护的配置管理。
60 0
|
4月前
|
缓存 Java 数据库连接
Spring Boot 资源文件属性配置,紧跟技术热点,为你的应用注入灵动活力!
【8月更文挑战第29天】在Spring Boot开发中,资源文件属性配置至关重要,它让开发者能灵活定制应用行为而不改动代码,极大提升了可维护性和扩展性。Spring Boot支持多种配置文件类型,如`application.properties`和`application.yml`,分别位于项目的resources目录下。`.properties`文件采用键值对形式,而`yml`文件则具有更清晰的层次结构,适合复杂配置。此外,Spring Boot还支持占位符引用和其他外部来源的属性值,便于不同环境下覆盖默认配置。通过合理配置,应用能快速适应各种环境与需求变化。
52 0