赞
踩
通过上篇代码可知,我们只需要使用 @Value 注解,就能完成属性的注入。而 @Value 基于 Environment 的机制。我们先来看一下 @Value的注入过程,而 @Value 基于 Environment 的机制,具体请参考spring-cloud-config 源码解析,本文主要讲Environment初始化过程。
在spring boot的启动流程中,有一个 prepareEnvironment 方法,这个方法就是用来准备Environment这个对象的,
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { //根据上下文,创建一个合适的Environment对象 ConfigurableEnvironment environment = getOrCreateEnvironment(); //配置Environment的propertySource、以及profile configureEnvironment(environment, applicationArguments.getSourceArgs()); ConfigurationPropertySources.attach(environment); // 通知监听器,加载配置文件 listeners.environmentPrepared(environment); bindToSpringApplication(environment); if (!this.isCustomEnvironment) { environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; }
点击getOrCreateEnvironment() ,这个方法是根据当前的webApplication类型匹配对应的environment,当前默认的应该就是StandardServletEnvironment
private ConfigurableEnvironment getOrCreateEnvironment() { if (this.environment != null) { return this.environment; } switch (this.webApplicationType) { case SERVLET: return new StandardServletEnvironment(); case REACTIVE: return new StandardReactiveWebEnvironment(); default: return new StandardEnvironment(); } }
StandardServletEnvironment 是整个spring boot应用运行环境的实现类,后面所有的关于环境相关的配置操作都是基于这个类,它的类的结构图如下:
StandardServletEnvironment 的初始化过程
StandardServletEnvironment创建实例时会调用父类AbstractEnvironment无参构造器,AbstractEnvironment ,在这个类的构造方法中,会
调用一个自定义配置文件的方法customizePropertySources(). 这个方法被StandardServletEnvironment重写,所以最终调用StandardServletEnvironment 中的 customizePropertySources 方法
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
}
super.customizePropertySources(propertySources);
}
这里是将几个不同的配置源封装成 StubPropertySource 和JndiPropertySource添加到
MutablePropertySources 中,调用 addLast 是表示一直往最后的位置添加。
SERVLET_CONFIG_PROPERTY_SOURCE_NAME:servlet的配置信息
SERVLET_CONTEXT_PROPERTY_SOURCE_NAME: 这个是servlet初始化的上下文,也就是以前我们在web.xml中配置的 context-param 。
JNDI_PROPERTY_SOURCE_NAME: 加载jndi.properties配置信息。
MutablePropertySources
在上面的代码中可以看到,所有的外部资源配置都是添加到了一个MutablePropertySources对象中,这个对象封装了属性资源的集合。
在AbstractEnvironment 这个类里定义了MutablePropertySources。并且把这个MutablePropertySources作为参数传递给了ConfigurablePropertyResolver 配置解析器中,而这个配置解析器是一个PropertySourcesPropertyResolver 实例。
public abstract class AbstractEnvironment implements ConfigurableEnvironment {
private final MutablePropertySources propertySources = new MutablePropertySources();
private final ConfigurablePropertyResolver propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);
}
来看一下这个类关系图
AbstractEnvironment 实现了文件解析器ConfigurablePropertyResolver ,而在上面这段代码中我们把 MutablePropertySources 传递到PropertySourcesPropertyResolver 中。这样就可以让 AbstractEnvironment 具备文件解析的功能,只是这个功能,委托给了PropertySourcesPropertyResolver来实现
接下来再看SpringApplication.configureEnvironment()方法
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
//添加类型转化的服务
if (this.addConversionService) {
ConversionService conversionService = ApplicationConversionService.getSharedInstance();
environment.setConversionService((ConfigurableConversionService) conversionService);
}
//配置Environment中的propertysources
configurePropertySources(environment, args);
//配置profiles
configureProfiles(environment, args);
}
1 点击configurePropertySources()
protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
MutablePropertySources sources = environment.getPropertySources();
//设置defaultProperties属性来源,如果设置了默认属性,则会加载
if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties));
}
//设置commandLineProperties来源,如果设置了命令行参数,则会加载
if (this.addCommandLineProperties && args.length > 0) {
String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
if (sources.contains</
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。