Spring加载配置文件多种方式(@PropertySource等)
可以基于xml或纯java配置, 源码分析基于Spring 5.2.5, 为了简洁会省去部分源码.
本文章讲的是properties文件. 顺带一提, 在spring引入xml文件:<import>或@ImportResource
方式一: @PropertySource
// 该例子来自于源码, 引入的后的properties文件也可以通过@Value("${}")使用
@Configuration
@PropertySource("classpath:/com/${my.placeholder:default/path}/app.properties")
public class AppConfig {
@Autowired
Environment env;
@Bean
public TestBean testBean() {
TestBean testBean = new TestBean();
testBean.setName(env.getProperty("testbean.name"));
return testBean;
}
}
@PropertySource由ConfigurationClassParser
处理, 并生成PropertySource
(ResourcePropertySource), 添加到Environment
(StandardServletEnvironment)(参考第18行)
class ConfigurationClassParser {
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
}
}
private void addPropertySource(PropertySource<?> propertySource) {
MutablePropertySources propertySources = ((ConfigurableEnvironment) this.environment).getPropertySources();
//...
propertySources.addLast(propertySource);
}
}
注意, 对于springboot是通过EnvironmentPostProcessor(ConfigDataEnvironmentPostProcessor)处理配置文件(application.properties/yml等), 最终同样是生成
PropertySource
(OriginTrackedMapPropertySource), 添加到Environment
(ApplicationServletEnvironment).具体加载方式参考:
YamlPropertySourceLoader
和PropertiesPropertySourceLoader
.(基于源码springboot 2.7.2)
方式二: <context:property-placeholder>
<context:property-placeholder location="my.properties" />
该方式会由**PropertySourcesPlaceholderConfigurer
**处理(该类本身也是spring管理), 并生成PropertySource
(PropertiesPropertySource), 并保存(第22行的mergeProperties()加载location)
注意使用该标签后, 上述的Environment也会被添加到该类(第11行).
public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerSupport implements EnvironmentAware {
private MutablePropertySources propertySources;
private PropertySources appliedPropertySources;
private Environment environment;
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (this.propertySources == null) {
this.propertySources = new MutablePropertySources();
if (this.environment != null) {
this.propertySources.addLast(
new PropertySource<Environment>(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) {
@Override
public String getProperty(String key) {
return this.source.getProperty(key);
}
}
);
}
try {
PropertySource<?> localPropertySource =
new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, mergeProperties());
if (this.localOverride) {
this.propertySources.addFirst(localPropertySource);
}
else {
this.propertySources.addLast(localPropertySource);
}
}
catch (IOException ex) {
throw new BeanInitializationException("Could not load properties", ex);
}
}
// 处理占位符"${}", 为beanFactory添加StringValueResolver等
// 参考:AbstractBeanFactory#resolveEmbeddedValue
processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources));
this.appliedPropertySources = this.propertySources;
}
// 从这里可以获取所有的PropertySource(MutablePropertySources)
public PropertySources getAppliedPropertySources() throws IllegalStateException {
return this.appliedPropertySources;
}
}
注意在springboot中该类在
PropertyPlaceholderAutoConfiguration
生成在传统spring中该类在
ContextNamespaceHandler->PropertyPlaceholderBeanDefinitionParser
生成