来宾网站建设,网址百度刷排名,h5制作软件紫色logo,ps做网站首页怎么SpringCloud项目启动过程中会解析bootstrop.properties、bootstrap.yaml配置文件#xff0c;启动父容器#xff0c;在子容器启动过程中会加入PropertySourceBootstrapConfiguration来读取配置中心的配置。
PropertySourceBootstrapConfiguration#initialize
PropertySource…
SpringCloud项目启动过程中会解析bootstrop.properties、bootstrap.yaml配置文件启动父容器在子容器启动过程中会加入PropertySourceBootstrapConfiguration来读取配置中心的配置。
PropertySourceBootstrapConfiguration#initialize
PropertySourceBootstrapConfiguration是SpringCloud的配置类实现了ApplicationContextInitializer会在容器创建前调用其initialize()方法。 org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration#initialize
public void initialize(ConfigurableApplicationContext applicationContext) {ListPropertySource? composite new ArrayList();AnnotationAwareOrderComparator.sort(this.propertySourceLocators);boolean empty true;ConfigurableEnvironment environment applicationContext.getEnvironment();for (PropertySourceLocator locator : this.propertySourceLocators) {// 调用PropertySourceLocator.locateCollection()来读取配置CollectionPropertySource? source locator.locateCollection(environment);if (source null || source.size() 0) {continue;}ListPropertySource? sourceList new ArrayList();for (PropertySource? p : source) {if (p instanceof EnumerablePropertySource) {EnumerablePropertySource? enumerable (EnumerablePropertySource?) p;sourceList.add(new BootstrapPropertySource(enumerable));}else {sourceList.add(new SimpleBootstrapPropertySource(p));}}logger.info(Located property source: sourceList);composite.addAll(sourceList);empty false;}if (!empty) {MutablePropertySources propertySources environment.getPropertySources();String logConfig environment.resolvePlaceholders(${logging.config:});LogFile logFile LogFile.get(environment);for (PropertySource? p : environment.getPropertySources()) {if (p.getName().startsWith(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {propertySources.remove(p.getName());}}insertPropertySources(propertySources, composite);reinitializeLoggingSystem(environment, logConfig, logFile);setLogLevels(applicationContext, environment);handleIncludedProfiles(environment);}
}在PropertySourceBootstrapConfiguration这个单例对象初始化的时候会将Spring容器中所有的PropertySourceLocator实现注入进来。然后在initialize()方法中循环所有的PropertySourceLocator进行配置的获取从这儿可以看出SpringCloud应用是支持我们引入多个配置中心实现的获取到配置后调用insertPropertySources方法将所有的PropertySource封装的一个个配置文件添加到Spring的环境变量environment中。
org.springframework.cloud.bootstrap.config.PropertySourceLocator#locateCollection(org.springframework.core.env.Environment)
default CollectionPropertySource? locateCollection(Environment environment) {return locateCollection(this, environment);
}static CollectionPropertySource? locateCollection(PropertySourceLocator locator,Environment environment) {// 最终会调用PropertySourceLocator.locate()PropertySource? propertySource locator.locate(environment);if (propertySource null) {return Collections.emptyList();}if (CompositePropertySource.class.isInstance(propertySource)) {CollectionPropertySource? sources ((CompositePropertySource) propertySource).getPropertySources();ListPropertySource? filteredSources new ArrayList();for (PropertySource? p : sources) {if (p ! null) {filteredSources.add(p);}}return filteredSources;}else {return Arrays.asList(propertySource);}
}上面会将CompositePropertySource拆分为多个PropertySource。
NacosPropertySourceLocator#locate
Nacos也实现了SpringCloud配置中心规范其实现类为NacosPropertySourceLocator。
com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#locate
public PropertySource? locate(Environment env) {nacosConfigProperties.setEnvironment(env);ConfigService configService nacosConfigManager.getConfigService();if (null configService) {log.warn(no instance of config service found, cant load config from nacos);return null;}long timeout nacosConfigProperties.getTimeout();nacosPropertySourceBuilder new NacosPropertySourceBuilder(configService,timeout);String name nacosConfigProperties.getName();String dataIdPrefix nacosConfigProperties.getPrefix();if (StringUtils.isEmpty(dataIdPrefix)) {dataIdPrefix name;}if (StringUtils.isEmpty(dataIdPrefix)) {dataIdPrefix env.getProperty(spring.application.name);}CompositePropertySource composite new CompositePropertySource(NACOS_PROPERTY_SOURCE_NAME);// 读取共享配置loadSharedConfiguration(composite);// 读取扩展配置loadExtConfiguration(composite);// 读取应用配置loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env);return composite;
}Nacos启动会加载以下三种配置文件也就是我们在bootstrap.yml文件里配置的扩展配置extension-configs、共享配置 shared-configs以及应用自己的配置加载到配置文件后会封装成NacosPropertySource返回最后只会返回一个CompositePropertySource。
NacosPropertySourceLocator#loadApplicationConfiguration
实际开发过程中我们主要使用的就是应用配置所以这里重点关注应用配置的加载过程。
com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#loadApplicationConfiguration
private void loadApplicationConfiguration(CompositePropertySource compositePropertySource, String dataIdPrefix,NacosConfigProperties properties, Environment environment) {String fileExtension properties.getFileExtension();String nacosGroup properties.getGroup();// load directly once by defaultloadNacosDataIfPresent(compositePropertySource, dataIdPrefix, nacosGroup,fileExtension, true);// load with suffix, which have a higher priority than the defaultloadNacosDataIfPresent(compositePropertySource,dataIdPrefix DOT fileExtension, nacosGroup, fileExtension, true);// Loaded with profile, which have a higher priority than the suffixfor (String profile : environment.getActiveProfiles()) {String dataId dataIdPrefix SEP1 profile DOT fileExtension;loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup,fileExtension, true);}}加载应用配置时同时会加载以下三种配置配置的优先级从低到高分别是
不带扩展名后缀application带扩展名后缀application.yml、application.propertie带环境带扩展名后缀application-prod.yml
com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#loadNacosDataIfPresent
private void loadNacosDataIfPresent(final CompositePropertySource composite,final String dataId, final String group, String fileExtension,boolean isRefreshable) {if (null dataId || dataId.trim().length() 1) {return;}if (null group || group.trim().length() 1) {return;}NacosPropertySource propertySource this.loadNacosPropertySource(dataId, group,fileExtension, isRefreshable);this.addFirstPropertySource(composite, propertySource, false);
}com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#loadNacosPropertySource
private NacosPropertySource loadNacosPropertySource(final String dataId,final String group, String fileExtension, boolean isRefreshable) {if (NacosContextRefresher.getRefreshCount() ! 0) {if (!isRefreshable) {// 从缓冲中获取return NacosPropertySourceRepository.getNacosPropertySource(dataId,group);}}return nacosPropertySourceBuilder.build(dataId, group, fileExtension,isRefreshable);
}com.alibaba.cloud.nacos.client.NacosPropertySourceBuilder#build
NacosPropertySource build(String dataId, String group, String fileExtension,boolean isRefreshable) {// 加载数据ListPropertySource? propertySources loadNacosData(dataId, group,fileExtension);NacosPropertySource nacosPropertySource new NacosPropertySource(propertySources,group, dataId, new Date(), isRefreshable);// 加入缓存NacosPropertySourceRepository.collectNacosPropertySource(nacosPropertySource);return nacosPropertySource;
}com.alibaba.cloud.nacos.client.NacosPropertySourceBuilder#loadNacosData
private ListPropertySource? loadNacosData(String dataId, String group,String fileExtension) {String data null;try {// 委托configService获取配置我们也可以手动使用此类获取配置data configService.getConfig(dataId, group, timeout);if (StringUtils.isEmpty(data)) {log.warn(Ignore the empty nacos configuration and get it based on dataId[{}] group[{}],dataId, group);return Collections.emptyList();}if (log.isDebugEnabled()) {log.debug(String.format(Loading nacos data, dataId: %s, group: %s, data: %s, dataId,group, data));}return NacosDataParserHandler.getInstance().parseNacosData(dataId, data,fileExtension);}catch (NacosException e) {log.error(get data from Nacos error,dataId:{} , dataId, e);}catch (Exception e) {log.error(parse data from Nacos error,dataId:{},data:{}, dataId, data, e);}return Collections.emptyList();
}loadNacosData()方法中会将实际配置加载请求委托给ConfigService去做然后解析返回的字符串解析器实现了PropertySourceLoader接口支持yml、properties、xml、json这几种格式。
NacosConfigService#getConfig
getConfig()方法会调用到getConfigInner()方法通过namespace, dataId, group唯一定位一个配置文件。
com.alibaba.nacos.client.config.NacosConfigService#getConfig
public String getConfig(String dataId, String group, long timeoutMs) throws NacosException {return getConfigInner(namespace, dataId, group, timeoutMs);
}首先获取本地缓存文件的配置内容如果有直接返回如果从本地没找到相应配置文件就从远程服务器拉取Nacos2.0以上版本使用Grpc协议进行远程通信1.0及以下使用Http协议进行远程通信我们这里使用的是1.4.2版本。 com.alibaba.nacos.client.config.NacosConfigService#getConfigInner
private String getConfigInner(String tenant, String dataId, String group, long timeoutMs) throws NacosException {group blank2defaultGroup(group);ParamUtils.checkKeyParam(dataId, group);ConfigResponse cr new ConfigResponse();cr.setDataId(dataId);cr.setTenant(tenant);cr.setGroup(group);// 优先使用本地配置String content LocalConfigInfoProcessor.getFailover(agent.getName(), dataId, group, tenant);if (content ! null) {LOGGER.warn([{}] [get-config] get failover ok, dataId{}, group{}, tenant{}, config{}, agent.getName(),dataId, group, tenant, ContentUtils.truncateContent(content));cr.setContent(content);String encryptedDataKey LocalEncryptedDataKeyProcessor.getEncryptDataKeyFailover(agent.getName(), dataId, group, tenant);cr.setEncryptedDataKey(encryptedDataKey);configFilterChainManager.doFilter(null, cr);content cr.getContent();return content;}try {// 从远程服务器拉取ConfigResponse response worker.getServerConfig(dataId, group, tenant, timeoutMs);cr.setContent(response.getContent());cr.setEncryptedDataKey(response.getEncryptedDataKey());configFilterChainManager.doFilter(null, cr);content cr.getContent();return content;} catch (NacosException ioe) {if (NacosException.NO_RIGHT ioe.getErrCode()) {throw ioe;}LOGGER.warn([{}] [get-config] get from server error, dataId{}, group{}, tenant{}, msg{},agent.getName(), dataId, group, tenant, ioe.toString());}LOGGER.warn([{}] [get-config] get snapshot ok, dataId{}, group{}, tenant{}, config{}, agent.getName(),dataId, group, tenant, ContentUtils.truncateContent(content));content LocalConfigInfoProcessor.getSnapshot(agent.getName(), dataId, group, tenant);cr.setContent(content);String encryptedDataKey LocalEncryptedDataKeyProcessor.getEncryptDataKeyFailover(agent.getName(), dataId, group, tenant);cr.setEncryptedDataKey(encryptedDataKey);// 这里会对配置进行拦截可以用于加解密configFilterChainManager.doFilter(null, cr);content cr.getContent();return content;
}com.alibaba.nacos.client.config.impl.ClientWorker#getServerConfig
public ConfigResponse getServerConfig(String dataId, String group, String tenant, long readTimeout)throws NacosException {ConfigResponse configResponse new ConfigResponse();if (StringUtils.isBlank(group)) {group Constants.DEFAULT_GROUP;}HttpRestResultString result null;try {MapString, String params new HashMapString, String(3);if (StringUtils.isBlank(tenant)) {params.put(dataId, dataId);params.put(group, group);} else {params.put(dataId, dataId);params.put(group, group);params.put(tenant, tenant);}// 调用远程Http接口/v1/cs/configs拉取配置result agent.httpGet(Constants.CONFIG_CONTROLLER_PATH, null, params, agent.getEncode(), readTimeout);} catch (Exception ex) {String message String.format([%s] [sub-server] get server config exception, dataId%s, group%s, tenant%s,agent.getName(), dataId, group, tenant);LOGGER.error(message, ex);throw new NacosException(NacosException.SERVER_ERROR, ex);}switch (result.getCode()) {case HttpURLConnection.HTTP_OK:LocalConfigInfoProcessor.saveSnapshot(agent.getName(), dataId, group, tenant, result.getData());configResponse.setContent(result.getData());String configType;if (result.getHeader().getValue(CONFIG_TYPE) ! null) {configType result.getHeader().getValue(CONFIG_TYPE);} else {configType ConfigType.TEXT.getType();}configResponse.setConfigType(configType);String encryptedDataKey result.getHeader().getValue(ENCRYPTED_DATA_KEY);LocalEncryptedDataKeyProcessor.saveEncryptDataKeySnapshot(agent.getName(), dataId, group, tenant, encryptedDataKey);configResponse.setEncryptedDataKey(encryptedDataKey);return configResponse;case HttpURLConnection.HTTP_NOT_FOUND:LocalConfigInfoProcessor.saveSnapshot(agent.getName(), dataId, group, tenant, null);LocalEncryptedDataKeyProcessor.saveEncryptDataKeySnapshot(agent.getName(), dataId, group, tenant, null);return configResponse;case HttpURLConnection.HTTP_CONFLICT: {LOGGER.error([{}] [sub-server-error] get server config being modified concurrently, dataId{}, group{}, tenant{}, agent.getName(), dataId, group, tenant);throw new NacosException(NacosException.CONFLICT,data being modified, dataId dataId ,group group ,tenant tenant);}case HttpURLConnection.HTTP_FORBIDDEN: {LOGGER.error([{}] [sub-server-error] no right, dataId{}, group{}, tenant{}, agent.getName(),dataId, group, tenant);throw new NacosException(result.getCode(), result.getMessage());}default: {LOGGER.error([{}] [sub-server-error] dataId{}, group{}, tenant{}, code{}, agent.getName(),dataId, group, tenant, result.getCode());throw new NacosException(result.getCode(),http error, code result.getCode() ,dataId dataId ,group group ,tenant tenant);}}
}至此在项目启动的时候上下文准备阶段我们就拉到了远程Nacos中的配置并且封装成NacosPropertySource放到了Spring 的环境变量里在Bean的实例化过程中就可以使用Environment中的值了。