Spring Cloud Config原理


最近学习SpringCloud感觉要疯了,硬着头皮写完了原理分析,有些原理理解的不是很透彻,还需要在琢磨琢磨。坚持吧!

1 @Value注解

通过上篇代码可知,我们只需要使用 @Value 注解,就能完成属性的注入。而 @Value 基于 Environment 的机制。我们先来看一下 @Value的注入过程,而 @Value 基于 Environment 的机制,具体请参考spring-cloud-config 源码解析,本文主要讲Environment初始化过程。

2 Spring Environment的初始化

在spring boot的启动流程中,有一个 prepareEnvironment 方法,这个方法就是用来准备Environment这个对象的,

  • springApplication.run -> prepareEnvironment
    这个方法主要就是创建和配置spring容器的环境信息,源码如下
	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;
	}

2.1 getOrCreateEnvironment

点击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来实现

2.2 configureEnvironment()

接下来再看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</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值