(1). 概述
今天在看Nacos的源码时,我发现:Nacos基于动态配置,并没有这样做:ConfigurableEnvironment.getPropertySources().addFirst(PropertySource),所以,特意写成一篇内容,记录下.
(2). 先看一个Spring的类(PropertySourceBootstrapConfiguration)
@Configuration
@EnableConfigurationProperties(PropertySourceBootstrapProperties.class)
public class PropertySourceBootstrapConfiguration
// 1. 很重要的实现,Spring在启动容器之前,会通过SPI,加载所有的实现类,并回调:initialize方法
implements ApplicationContextInitializer<ConfigurableApplicationContext>,
Ordered {
public static final String BOOTSTRAP_PROPERTY_SOURCE_NAME = BootstrapApplicationListener.BOOTSTRAP_PROPERTY_SOURCE_NAME+ "Properties";
private static Log logger = LogFactory.getLog(PropertySourceBootstrapConfiguration.class);
private int order = Ordered.HIGHEST_PRECEDENCE + 10;
// ********************************************************************
// 2. 注入在Spring容器里,所有PropertySourceLocator的实现类
// ********************************************************************
@Autowired(required = false)
private List<PropertySourceLocator> propertySourceLocators = new ArrayList<>();
public void initialize(ConfigurableApplicationContext applicationContext) {
// 3. 创建一个组合的:PropertySource
CompositePropertySource composite = new CompositePropertySource(BOOTSTRAP_PROPERTY_SOURCE_NAME);
// 4. 对propertySourceLocators进行排序
AnnotationAwareOrderComparator.sort(this.propertySourceLocators);
boolean empty = true;
// 5. 获得当前的上下文环境(ConfigurableEnvironment)
ConfigurableEnvironment environment = applicationContext.getEnvironment();
// 6. 回调所有的:PropertySourceLocator.locate方法
for (PropertySourceLocator locator : this.propertySourceLocators) {
PropertySource<?> source = null;
source = locator.locate(environment);
if (source == null) {
continue;
}
logger.info("Located property source: " + source);
composite.addPropertySource(source);
empty = false;
}// end for
if (!empty) {
// 7. 从ConfigurableEnvironment中获得MutablePropertySources载体(它承载着所有的:PropertySources,即配置信息)
MutablePropertySources propertySources = environment.getPropertySources();
// 8. 获得配置项:${logging.config:}
String logConfig = environment.resolvePlaceholders("${logging.config:}");
// 日志处理不必太关心
LogFile logFile = LogFile.get(environment);
if (propertySources.contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
propertySources.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME);
}
// **********************************************************
// 9. environment.getPropertySources().addLast(CompositePropertySource)
// **********************************************************
insertPropertySources(propertySources, composite);
// ... ...
}
} // end initialize
}
(3). 看一下PropertySourceLocator接口
public interface PropertySourceLocator {
// 传入Environment,返回一个:PropertySource(Nacos自己实现了它)
PropertySource<?> locate(Environment environment);
}
(4). NacosPropertySourceLocator
@Order(0)
public class NacosPropertySourceLocator implements PropertySourceLocator {
@Override
public PropertySource<?> locate(Environment env) {
// ... ...
CompositePropertySource composite = new CompositePropertySource(NACOS_PROPERTY_SOURCE_NAME);
// ... ...
return composite;
}
}
(5). 总结
Spring在设计上,真的值得大家学习,它永远都会留出回调函数给大家使用(完全符合开闭原则),而不需要改动现有的源码.