从Nacos看Spring环境初始化

首先,在Spring的run函数中

在实际的初始化及装载Bean之前,会进行初始化环境,方便Bean的初始化

对于Enviroment的初始化在SpringApplication#prepareEnviroment中

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {

ConfigurableEnvironment environment = this.getOrCreateEnvironment();

this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());

ConfigurationPropertySources.attach((Environment)environment);

listeners.environmentPrepared((ConfigurableEnvironment)environment);

this.bindToSpringApplication((ConfigurableEnvironment)environment);

if (!this.isCustomEnvironment) {

environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());

}

ConfigurationPropertySources.attach((Environment)environment);

return (ConfigurableEnvironment)environment;

}

在上述代码中,初始化了环境,

进行了环境的装载

主要入口在listeners中

在Listeners中,一路跟随onApplicationEvent进入到ConfigFileApplicationListener之中

在其中判断了是否是环境准备Event,然后执行环境初始化

public void onApplicationEvent(ApplicationEvent event) {

if (event instanceof ApplicationEnvironmentPreparedEvent) {

this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event);

}

if (event instanceof ApplicationPreparedEvent) {

this.onApplicationPreparedEvent(event);

}

}

在其中装载了Processor,然后排序后进行依次执行

private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {

List<EnvironmentPostProcessor> postProcessors = this.loadPostProcessors();

postProcessors.add(this);

AnnotationAwareOrderComparator.sort(postProcessors);

Iterator var3 = postProcessors.iterator();

while(var3.hasNext()) {

EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var3.next();

postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());

}

}

其中的loadPostProcessors()负责装载了处理器,传入了interface org.springframework.boot.env.EnvironmentPostProcessor来扫描反射获取类并实例化

这就引入出了我们第一个主角

EnvironmentPostProcessor接口了,其中提供了一个接口

public interface EnvironmentPostProcessor {

void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application);

}

负责处理环境变量

我们拿一个CloudFoundryProcessor来举例

public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {

if (CloudPlatform.CLOUD_FOUNDRY.isActive(environment)) {

Properties properties = new Properties();

JsonParser jsonParser = JsonParserFactory.getJsonParser();

this.addWithPrefix(properties, this.getPropertiesFromApplication(environment, jsonParser), “vcap.application.”);

this.addWithPrefix(properties, this.getPropertiesFromServices(environment, jsonParser), “vcap.services.”);

MutablePropertySources propertySources = environment.getPropertySources();

if (propertySources.contains(“commandLineArgs”)) {

propertySources.addAfter(“commandLineArgs”, new PropertiesPropertySource(“vcap”, properties));

} else {

propertySources.addFirst(new PropertiesPropertySource(“vcap”, properties));

}

}

}

在内部的操作并不困难,只需要根据自己的需求,往Enviroment中的PropertySources添加PropertySource接口的实现类即可

整体实现后,别忘在spring.factories进行生命此为配置处理器

然后就是Nacos实现

其实现了PropertySourceLocator接口

NacosPropertySourceLocator#locate接口

这个接口流程则是在实现了ApplicationContextIntializer中的PropertySourceBootstrapConfiguration中进行了初始化

获取到了实现了PropertySourceLocator接口的类,然后在其中循环遍历处理

PropertySourceLocator locator = (PropertySourceLocator)var5.next();

source = locator.locateCollection(environment);

在其中调用了NacosPropertySourceLocator

Nacos的内部实现为

首先装配了Nacos客户端

this.nacosConfigProperties.setEnvironment(env);

ConfigService configService = this.nacosConfigManager.getConfigService();

然后尝试去获取配置

long timeout = (long)this.nacosConfigProperties.getTimeout();

this.nacosPropertySourceBuilder = new NacosPropertySourceBuilder(configService, timeout);

String name = this.nacosConfigProperties.getName();

String dataIdPrefix = this.nacosConfigProperties.getPrefix();

if (StringUtils.isEmpty(dataIdPrefix)) {

dataIdPrefix = name;

}

if (StringUtils.isEmpty(dataIdPrefix)) {

dataIdPrefix = env.getProperty(“spring.application.name”);

}

CompositePropertySource composite = new CompositePropertySource(“NACOS”);

this.loadSharedConfiguration(composite);

this.loadExtConfiguration(composite);

this.loadApplicationConfiguration(composite, dataIdPrefix, this.nacosConfigProperties, env);

return composite;

这里返回composite,就是Nacos自己实现的PropertySource

方便Spring获取

里面维护了一个Map集合

Map里面是不同yml文件的数据

那么,Nacos的配置文件已经完成了

我们尝试实现一个自己的PropertySourceLocator

@Order(1)

public class MyPropertySourceLoader implements PropertySourceLocator {

@Override

public PropertySource<?> locate(Environment environment) {

StandardServletEnvironment myEnv = (StandardServletEnvironment) environment;

MutablePropertySources propertySources = myEnv.getPropertySources();

CompositePropertySource composite = new CompositePropertySource(“My”);

MyPropertySource myPropertySource = new MyPropertySource(“testProp”, “MyTest”);

composite.addPropertySource(myPropertySource);

return composite;

}

}

实现的PropertySource如下

class MyPropertySource<T> extends PropertySource {

private Map<String, T> propMap = new HashMap<>();

public MyPropertySource(String name, T source) {

super(name, source);

this.propMap.put(name, source);

}

@Override

public T getProperty(String name) {

return propMap.get(name);

}

}

这样就实现了一个基本的数据装配类

我们可以自定义从一些特殊地方获取配置,比如阿里云的密码管理 AWS的SerectManager

发表评论

邮箱地址不会被公开。 必填项已用*标注