Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说spring-context注解源码系列十——@PropertySource[通俗易懂],希望能够帮助你!!!。
Annotation providing a convenient and declarative mechanism for adding a {@link org.springframework.core.env.PropertySource PropertySource} to Spring’s {@link org.springframework.core.env.Environment Environment}.
提供了一种注解的机制,将配置文件中配置信息合并到spring的Environment中。
PropertySource可以将任意位置的配置文件合并到项目中,包括远程URL文件、服务器任意位置的文件等,只要是sping ResourceLoader可以加载到的配置文件都可以支持。
PropertySource默认支持读取properties文件和xml文件,通过传入自定义的factory也可以实现读取yaml文件。
@Configuration
@PropertySource(value = {"db.properties", "config.properties"})
public class ConditionalConfig {
public ConditionalService conditionalService() {
return new ConditionalService();
}
}
ConfigurationClassParser
ConfigurationClassParser的doProcessConfigurationClass方法的作用是读取配置类中的注解、内部类、方法等来完成配置类的解析,@PropertySource就是在这个时候被解析的,具体的解析逻辑在processPropertySource方法中。
/**
* Process the given <code>@PropertySource</code> annotation metadata.
* @param propertySource metadata for the <code>@PropertySource</code> annotation found
* @throws IOException if loading a property source failed
* 处理@PropertySource
*/
private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
// 解析 name 属性,没有则自动创建一个,用于配置信息合并
String name = propertySource.getString("name");
if (!StringUtils.hasLength(name)) {
name = null;
}
// 解析 encoding 属性
String encoding = propertySource.getString("encoding");
if (!StringUtils.hasLength(encoding)) {
encoding = null;
}
// 解析 value 属性,如果该属性为空,则会抛出异常
String[] locations = propertySource.getStringArray("value");
Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
// 解析 ignoreResourceNotFound 属性,ignoreResourceNotFound=true则不会抛出异常
boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");
// 解析 factory 属性,如果未设置,则使用默认的 DefaultPropertySourceFactory,否则使用传入的工厂
Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory");
PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ?
DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass));
// 根据配置的资源地址,逐个加载并设置给environment
for (String location : locations) {
try {
// 使用environment信息解析传入的配置文件地址,得到真正的地址
String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
// 使用资源加载器,自动识别并得到资源
Resource resource = this.resourceLoader.getResource(resolvedLocation);
// 创建资源并调用addPropertySource合并到当前的environment中
addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
}
catch (IllegalArgumentException | FileNotFoundException | UnknownHostException | SocketException ex) {
// Placeholders not resolvable or resource not found when trying to open it
// 如果忽略资源找不到的情况(ignoreResourceNotFound=true),则不抛出异常
if (ignoreResourceNotFound) {
if (logger.isInfoEnabled()) {
logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage());
}
}
else {
throw ex;
}
}
}
}
在processPropertySource中,读取@PropertySource的基本信息后创建EncodedResource实例,然后调用PropertySourceFactory的createPropertySource方法解析得到配置信息,最后调用addPropertySource方法将配置信息整合到environment中。
// 将加载到的属性设置给environment
private void addPropertySource(PropertySource<?> propertySource) {
String name = propertySource.getName();
MutablePropertySources propertySources = ((ConfigurableEnvironment) this.environment).getPropertySources();
if (this.propertySourceNames.contains(name)) {
// We've already added a version, we need to extend it
// propertySourceNames存在表示之前已经存储起来了,需要进行合并
PropertySource<?> existing = propertySources.get(name);
if (existing != null) {
PropertySource<?> newSource = (propertySource instanceof ResourcePropertySource ?
((ResourcePropertySource) propertySource).withResourceName() : propertySource);
if (existing instanceof CompositePropertySource) {
// 已经存在的如果是合并过(CompositePropertySource类型)的,则直接进行合并
((CompositePropertySource) existing).addFirstPropertySource(newSource);
}
else {
// 如果已经存在是未合并的,则新建一个CompositePropertySource并合2个propertySource
if (existing instanceof ResourcePropertySource) {
existing = ((ResourcePropertySource) existing).withResourceName();
}
CompositePropertySource composite = new CompositePropertySource(name);
composite.addPropertySource(newSource);
composite.addPropertySource(existing);
propertySources.replace(name, composite);
}
return;
}
}
// 将 propertySource 存储起来
if (this.propertySourceNames.isEmpty()) {
propertySources.addLast(propertySource);
}
else {
String firstProcessed = this.propertySourceNames.get(this.propertySourceNames.size() - 1);
propertySources.addBefore(firstProcessed, propertySource);
}
this.propertySourceNames.add(name);
}
今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
上一篇
已是最后文章
下一篇
已是最新文章