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

简介: 详解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的实现子类自己提供实现。

相关文章
|
5天前
|
存储 Java 数据安全/隐私保护
|
5天前
|
XML JavaScript Java
【JavaEE】Spring Boot - 配置文件
【JavaEE】Spring Boot - 配置文件
7 0
|
5天前
|
XML Java 数据格式
Spring 属性注入方式
Spring 属性注入方式
14 2
|
5天前
|
Java 数据库连接 数据库
Spring事务简介,事务角色,事务属性
Spring事务简介,事务角色,事务属性
20 2
|
5天前
|
Java Apache Spring
Spring BeanUtils与Apache BeanUtils提供基本属性复制,适用于简单需求
【5月更文挑战第4天】Spring BeanUtils与Apache BeanUtils提供基本属性复制,适用于简单需求;Cglib BeanCopier用于转换为Cglib代理对象;Apache PropertyUtils处理属性操作;Dozer支持复杂对象映射。选择工具取决于具体需求,如需精细控制或对象映射,推荐Dozer或Apache PropertyUtils。Apache BeanUtils可能因潜在的封装性破坏被禁用。
24 3
|
5天前
|
Java 开发者 Spring
Spring Boot中的资源文件属性配置
【4月更文挑战第28天】在Spring Boot应用程序中,配置文件是管理应用程序行为的重要组成部分。资源文件属性配置允许开发者在不重新编译代码的情况下,对应用程序进行灵活地配置和调整。本篇博客将介绍Spring Boot中资源文件属性配置的基本概念,并通过实际示例展示如何利用这一功能。
27 1
|
5天前
|
JSON Java 数据库连接
属性注入掌握:Spring Boot配置属性的高级技巧与最佳实践
属性注入掌握:Spring Boot配置属性的高级技巧与最佳实践
28 1
|
5天前
|
XML Java 关系型数据库
注解驱动事务:Spring中基于注解的事务属性配置详解
注解驱动事务:Spring中基于注解的事务属性配置详解
43 0
注解驱动事务:Spring中基于注解的事务属性配置详解
|
5天前
|
Java 应用服务中间件 Maven
SpringBoot 项目瘦身指南
SpringBoot 项目瘦身指南
62 0
|
5天前
|
缓存 安全 Java
Spring Boot 面试题及答案整理,最新面试题
Spring Boot 面试题及答案整理,最新面试题
142 0