那么问题来了,为何使用PropertySourcesPlaceholderConfigurer,只需要简单的new一个就成了勒(并不需要手动设置location)?
一样的,从源码处一看便知,非常非常简单:
// @since 3.1 直接实现了EnvironmentAware,说明此Bean可以拿到当前环境Environment public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerSupport implements EnvironmentAware { ... @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { ... // 把环境属性都放进来~ if (this.environment != null) { this.propertySources.addLast( new PropertySource<Environment>(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) { @Override @Nullable public String getProperty(String key) { return this.source.getProperty(key); } } ); } // 把配置的属性放进来~~~ PropertySource<?> localPropertySource = new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, mergeProperties()); this.propertySources.addFirst(localPropertySource); ... } }
相信不用我做过多的解释,就知道为何不用自己设置location,直接使用注解@PropertySource("classpath:my.properties")
就好使了吧。这个时候环境截图如下(注意:此处我截图是基于已经set了location
的截图哦):
what?虽然配置时候set了location去加载属性文件,但是上面代码中add进去的属性源environmentProperties和localProperties
public static final String LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME = "localProperties"; public static final String ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME = "environmentProperties";
两个PropertySource都并没有出现?
关于此,我这里就不再解释了,哈哈。还是那句话,留给小伙伴们自己思考,若思考不明白的亦可扫码入群探讨哦~(当然参照上面文章也是可行的)
SpringBoot工程下使用
关于在SpringBoot中使用,简单到令人发指,毕竟SpringBoot的使命也是让你使用它能够简单到木有朋友。
so,在SpringBoot工程下使用@ImportResource和@PropertySource啥都不用配,它是能够天然的直接work的~
原因分析如下:
一切得益于SpringBoot强悍的自动化配置能力,它提供了这样一个配置类:
@Configuration @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) // 最高优先级 public class PropertyPlaceholderAutoConfiguration { // 注意此处使用的是PropertySourcesPlaceholderConfigurer // 并且你可以在本容器内覆盖它的默认行为哟~~~~ @Bean @ConditionalOnMissingBean(search = SearchStrategy.CURRENT) public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } }
PropertyPlaceholderAutoConfiguration它被配置在了自动配置包下的spring.factories文件里:
# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ ... org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\ ...
因此它会随着工程启动而自动生效。有了上面对Spring工程下的使用分析,此处就不用再花笔墨解释了~
另外附加说明一点:哪怕你的属性不使用@PropertySource导入,而是写在SB自带的application.properties文件里,依旧是没有问题的。
原因分析如下:
其实这个涉及到的是SpringBoot对application.properties的加载时机问题,因为本文对SB的介绍并不是重点,因此此处我直接简单的说出结论即止:
- SpringBoot通过事件监听机制加载很多东西,加载此属性文件用的是ConfigFileApplicationListener这个监听器
- 它监听到ApplicationEnvironmentPreparedEvent(环境准备好后)事件后开始加载application.properties等文件
- ApplicationEnvironmentPreparedEvent的事件发出是发生在createApplicationContext()之前~~~ 部分代码如下:
public class SpringApplication { ... public ConfigurableApplicationContext run(String... args) { ... ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 此步骤 会发出ApplicationEnvironmentPreparedEvent事件 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); Banner printedBanner = printBanner(environment); // 开始创建,初始化容器~ context = createApplicationContext(); ... } ... }
so,在SB环境下已经早早把属性都放进环境内了,借助它默认配置好的PropertySourcesPlaceholderConfigurer来处理的,那可不能正常work吗。一切都是这么自然,这或许就是SB的魅力所在吧~
关于小伙伴问题的解决
开头提出了问题,肯定得解决问题嘛~~~如下图
哈哈,虽然最终我并没有直接的帮助解决问题,但是此问题给了我写本文的动力,总体还是不错的~
总结
本文通过一个小伙伴咨询的小问题(真是小问题吗?)引申比较详细的说了Spring在处理占位符这块的内容(其实本并没打算写这么多的,尴尬~)
写本文的目的开头也说了,我认为在SpringBoot还并非100%渗透的当下,肯定有人会遇到从传统Spring项目向SpringBoot过度的一个阶段,而本文的描述或许能给你的迁移提供一种新的思路(特别是时间紧、任务重的时候),希望小伙伴们能有所收获,peace~