After understanding the basic principle of the above Environment, how to load the configuration from the remote server into the Spring Environment.
NacosPropertySourceLocator
Following the above analysis ideas, we naturally went to find the implementation class of PropertySourceLocator and found that in addition to our customized GpJsonPropertySourceLocator, there is another implementation class NacosPropertySourceLocator
So, let's directly look at the locate method in NacosPropertySourceLocator. The code is as follows.
public PropertySource<?> locate(Environment env) { this.nacosConfigProperties.setEnvironment(env); ConfigService configService = this.nacosConfigManager.getConfigService(); if (null == configService) { log.warn("no instance of config service found, can't load config from nacos"); return null; } else { //Gets the timeout configured by the client long timeout = (long)this.nacosConfigProperties.getTimeout(); this.nacosPropertySourceBuilder = new NacosPropertySourceBuilder(configService, timeout); //Get the name attribute, String name = this.nacosConfigProperties.getName(); //In Spring Cloud, the default name is spring application. name. String dataIdPrefix = this.nacosConfigProperties.getPrefix(); if (StringUtils.isEmpty(dataIdPrefix)) { dataIdPrefix = name; } if (StringUtils.isEmpty(dataIdPrefix)) { dataIdPrefix = env.getProperty("spring.application.name"); //Get spring application. Name, assigned to dataIdPrefix } //Create a Composite property source that can contain multiple propertysources CompositePropertySource composite = new CompositePropertySource("NACOS"); this.loadSharedConfiguration(composite); //Load shared configuration //Load extended configuration loadExtConfiguration(composite); //Load own configuration loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env); return composite; } }
The implementation of the above code is not difficult to understand
- Get the configuration properties of the nacos client and generate the dataId (this is very important to locate the nacos configuration)
- Call three methods respectively to load the configuration attribute source and save it to the composite composite attribute source
loadApplicationConfiguration
Regardless of the method of loading shared configuration and extended configuration, we can read the configuration from the remote service in essence, but the incoming parameters are different.
- fileExtension, which indicates the extension of the configuration file
- nacosGroup stands for grouping
- Load configuration with dataid = project name
- Load the configuration with dataid = project name + extension
- Traverse the currently configured activation point (profile) and load the dataid configuration with profile circularly
private void loadApplicationConfiguration( CompositePropertySource compositePropertySource, String dataIdPrefix, NacosConfigProperties properties, Environment environment) { String fileExtension = properties.getFileExtension(); //The default extension is: properties String nacosGroup = properties.getGroup(); //Get group //Load the configuration of 'dataid = project name' loadNacosDataIfPresent(compositePropertySource, dataIdPrefix, nacosGroup, fileExtension, true); //Load the configuration of 'dataid = project name + extension' loadNacosDataIfPresent(compositePropertySource, dataIdPrefix + DOT + fileExtension, nacosGroup, fileExtension, true); // Traverse the profile (there can be multiple), and load the configuration according to the profile for (String profile : environment.getActiveProfiles()) { //Dataid = ${spring. Application. Name}$ {profile}.$ {fileExtension} String dataId = dataIdPrefix + SEP1 + profile + DOT + fileExtension; loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup, fileExtension, true); } }
loadNacosDataIfPresent
Call loadNacosPropertySource to load the existing configuration information.
Save the loaded configuration properties to CompositePropertySource.
private void loadNacosDataIfPresent(final CompositePropertySource composite, final String dataId, final String group, String fileExtension, boolean isRefreshable) { //If the dataId is empty or the group is empty, skip directly if (null == dataId || dataId.trim().length() < 1) { return; } if (null == group || group.trim().length() < 1) { return; } //Get attribute source from nacos NacosPropertySource propertySource = this.loadNacosPropertySource(dataId, group, fileExtension, isRefreshable); //Save the property source to compositePropertySource this.addFirstPropertySource(composite, propertySource, false); }
loadNacosPropertySource
private NacosPropertySource loadNacosPropertySource(final String dataId, final String group, String fileExtension, boolean isRefreshable) { if (NacosContextRefresher.getRefreshCount() != 0) { if (!isRefreshable) { //Whether automatic refresh is supported, / / if automatic refresh configuration is not supported, it will be automatically obtained from the cache and returned (not loaded from the remote server) return NacosPropertySourceRepository.getNacosPropertySource(dataId, group); } } //The constructor obtains data from the configuration center return nacosPropertySourceBuilder.build(dataId, group, fileExtension, isRefreshable); }
NacosPropertySourceBuilder.build
NacosPropertySource build(String dataId, String group, String fileExtension, boolean isRefreshable) { //Call loadNacosData to load remote data List<PropertySource<?>> propertySources = loadNacosData(dataId, group, fileExtension); //Construct Nacos PropertySource (this is the PropertySource of Nacos custom extension, which is similar to the custom PropertySource we demonstrated earlier). // It is equivalent to saving the data obtained from the remote server to the NacosPropertySource. NacosPropertySource nacosPropertySource = new NacosPropertySource(propertySources, group, dataId, new Date(), isRefreshable); //Cache properties to local cache NacosPropertySourceRepository.collectNacosPropertySource(nacosPropertySource); return nacosPropertySource; }
NacosPropertySourceBuilder.loadNacosData
This method is to connect to the remote server to obtain the configuration data. The key code is configservice getConfig
private List<PropertySource<?>> loadNacosData(String dataId, String group, String fileExtension) { String data = null; try { data = configService.getConfig(dataId, group, timeout); //Load Nacos configuration data 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)); } //Parse the loaded data and save it to the list < propertysource > collection. 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(); }
Phased summary
Through the above analysis, we know the key path when Spring Cloud integrates Nacos, and that Spring Cloud will load dynamic data from Nacos Server and save it to the Environment collection at startup.
So as to realize the automatic injection of dynamic configuration.
Data loading process of Nacos client
The final loading of configuration data is based on configservice Getconfig is implemented by the SDK provided by Nacos.
public String getConfig(String dataId, String group, long timeoutMs) throws NacosException
Tutorial on using the Nacos SDK: https://nacos.io/zh-cn/docs/s...
In other words, next, our source code analysis directly enters the category of Nacos.
NacosConfigService.getConfig
@Override public String getConfig(String dataId, String group, long timeoutMs) throws NacosException { return getConfigInner(namespace, dataId, group, timeoutMs); }
private String getConfigInner(String tenant, String dataId, String group, long timeoutMs) throws NacosException { group = blank2defaultGroup(group); //Get group. If it is empty, it is default group ParamUtils.checkKeyParam(dataId, group); //Validation request parameters ConfigResponse cr = new ConfigResponse(); //Set response results cr.setDataId(dataId); cr.setTenant(tenant); cr.setGroup(group); // Local configuration is preferred String content = LocalConfigInfoProcessor.getFailover(agent.getName(), dataId, group, tenant); if (content != null) { //If the content in the local cache is not empty LOGGER.warn("[{}] [get-config] get failover ok, dataId={}, group={}, tenant={}, config={}", agent.getName(), dataId, group, tenant, ContentUtils.truncateContent(content)); cr.setContent(content); //Set the content to cr. //Get the encryptedDataKey of disaster recovery configuration String encryptedDataKey = LocalEncryptedDataKeyProcessor .getEncryptDataKeyFailover(agent.getName(), dataId, group, tenant); cr.setEncryptedDataKey(encryptedDataKey); //Save to cr configFilterChainManager.doFilter(null, cr); //Execute filtering (it doesn't seem to be implemented at present) content = cr.getContent(); //Return file content return content; } //If there is no relevant content in the local file, a remote call is initiated try { ConfigResponse response = worker.getServerConfig(dataId, group, tenant, timeoutMs); //Return the response content 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()); } //If there is a NacosException and it is not 403 exception, try to get the configuration through the local snapshot file and return. 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; }
Read configuration from local cache
By default, Nacos first reads the file from the locally cached configuration: C:\Users\mayn\nacos\config\fixed-192.168.8.133_8848-6a382560-ed4c-414c-a5e2-9d72c48f1a0e_nacos
If the local cached content exists, the content data is returned; otherwise, a null value is returned.
public static String getFailover(String serverName, String dataId, String group, String tenant) { File localPath = getFailoverFile(serverName, dataId, group, tenant); if (!localPath.exists() || !localPath.isFile()) { return null; } try { return readFile(localPath); } catch (IOException ioe) { LOGGER.error("[" + serverName + "] get failover error, " + localPath, ioe); return null; } }
Read the file contents from the specified file directory.
static File getFailoverFile(String serverName, String dataId, String group, String tenant) { File tmp = new File(LOCAL_SNAPSHOT_PATH, serverName + "_nacos"); tmp = new File(tmp, "data"); if (StringUtils.isBlank(tenant)) { tmp = new File(tmp, "config-data"); } else { tmp = new File(tmp, "config-data-tenant"); tmp = new File(tmp, tenant); } return new File(new File(tmp, group), dataId); }
ClientWorker.getServerConfig
ClientWorker represents a working class of the client, which is responsible for interacting with the server.
public ConfigResponse getServerConfig(String dataId, String group, String tenant, long readTimeout) throws NacosException { ConfigResponse configResponse = new ConfigResponse(); if (StringUtils.isBlank(group)) { //If group is empty, the default group is returned group = Constants.DEFAULT_GROUP; } HttpRestResult<String> result = null; try { Map<String, String> params = new HashMap<String, String>(3); //Build request parameters 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); } //Initiate remote call 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); } //Different processing is realized according to the response results switch (result.getCode()) { case HttpURLConnection.HTTP_OK: //If the response is successful, save the snapshot locally and return the response content LocalConfigInfoProcessor.saveSnapshot(agent.getName(), dataId, group, tenant, result.getData()); configResponse.setContent(result.getData()); String configType; //Type of configuration file, such as text, json, yaml, etc if (result.getHeader().getValue(CONFIG_TYPE) != null) { configType = result.getHeader().getValue(CONFIG_TYPE); } else { configType = ConfigType.TEXT.getType(); } configResponse.setConfigType(configType); //Set it to configResponse, and then implement different parsing strategies according to the file type //Get the key of encrypted data String encryptedDataKey = result.getHeader().getValue(ENCRYPTED_DATA_KEY); //preservation LocalEncryptedDataKeyProcessor .saveEncryptDataKeySnapshot(agent.getName(), dataId, group, tenant, encryptedDataKey); configResponse.setEncryptedDataKey(encryptedDataKey); return configResponse; case HttpURLConnection.HTTP_NOT_FOUND: //If 404 is returned, empty the local snapshot 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); } } }
ServerHttpAgent.httpGet
Implementation of remote request.
@Override public HttpRestResult<String> httpGet(String path, Map<String, String> headers, Map<String, String> paramValues, String encode, long readTimeoutMs) throws Exception { final long endTime = System.currentTimeMillis() + readTimeoutMs; injectSecurityInfo(paramValues); //Inject security information String currentServerAddr = serverListMgr.getCurrentServerAddr();//Get the current server address int maxRetry = this.maxRetry; //Gets the maximum number of retries. The default is 3 //Configure the properties of HttpClient. The default readTimeOut timeout is 3s HttpClientConfig httpConfig = HttpClientConfig.builder() .setReadTimeOutMillis(Long.valueOf(readTimeoutMs).intValue()) .setConTimeOutMillis(ConfigHttpClientManager.getInstance().getConnectTimeoutOrDefault(100)).build(); do { try { //Set header Header newHeaders = getSpasHeaders(paramValues, encode); if (headers != null) { newHeaders.addAll(headers); } //Building query criteria Query query = Query.newInstance().initParams(paramValues); //Initiate an HTTP request, http://192.168.8.133:8848/nacos/v1/cs/configs HttpRestResult<String> result = NACOS_RESTTEMPLATE .get(getUrl(currentServerAddr, path), httpConfig, newHeaders, query, String.class); if (isFail(result)) { //If the request fails, LOGGER.error("[NACOS ConnectException] currentServerAddr: {}, httpCode: {}", serverListMgr.getCurrentServerAddr(), result.getCode()); } else { // Update the currently available server addr serverListMgr.updateCurrentServerAddr(currentServerAddr); return result; } } catch (ConnectException connectException) { LOGGER.error("[NACOS ConnectException httpGet] currentServerAddr:{}, err : {}", serverListMgr.getCurrentServerAddr(), connectException.getMessage()); } catch (SocketTimeoutException socketTimeoutException) { LOGGER.error("[NACOS SocketTimeoutException httpGet] currentServerAddr:{}, err : {}", serverListMgr.getCurrentServerAddr(), socketTimeoutException.getMessage()); } catch (Exception ex) { LOGGER.error("[NACOS Exception httpGet] currentServerAddr: " + serverListMgr.getCurrentServerAddr(), ex); throw ex; } //If there are multiple servers in the list and the current request fails, try to retry with the next address if (serverListMgr.getIterator().hasNext()) { currentServerAddr = serverListMgr.getIterator().next(); } else { maxRetry--; //The number of retries decreases if (maxRetry < 0) { throw new ConnectException( "[NACOS HTTP-GET] The maximum number of tolerable server reconnection errors has been reached"); } serverListMgr.refreshCurrentServerAddr(); } } while (System.currentTimeMillis() <= endTime); LOGGER.error("no available server"); throw new ConnectException("no available server"); }
Configuration acquisition of Nacos Server
The client loads the configuration to the server, and the called interface is: / nacos/v1/cs/configs. Therefore, find the interface in the source code of Nacos
Locate the configcontroller in the Nacos source code The code of the method in getconfig is as follows:
@GetMapping @Secured(action = ActionTypes.READ, parser = ConfigResourceParser.class) public void getConfig(HttpServletRequest request, HttpServletResponse response, @RequestParam("dataId") String dataId, @RequestParam("group") String group, @RequestParam(value = "tenant", required = false, defaultValue = StringUtils.EMPTY) String tenant, @RequestParam(value = "tag", required = false) String tag) throws IOException, ServletException, NacosException { // check tenant ParamUtils.checkTenant(tenant); tenant = NamespaceUtil.processNamespaceParameter(tenant); //Tenant, i.e. namespaceid // check params ParamUtils.checkParam(dataId, group, "datumId", "content"); //Check whether the request parameter is empty ParamUtils.checkParam(tag); final String clientIp = RequestUtil.getRemoteIp(request); //Get the requested ip inner.doGetConfig(request, response, dataId, group, tenant, tag, clientIp); //load configuration }
inner.doGetConfig
public String doGetConfig(HttpServletRequest request, HttpServletResponse response, String dataId, String group, String tenant, String tag, String clientIp) throws IOException, ServletException { final String groupKey = GroupKey2.getKey(dataId, group, tenant); String autoTag = request.getHeader("Vipserver-Tag"); String requestIpApp = RequestUtil.getAppName(request); //Application name of the requester int lockResult = tryConfigReadLock(groupKey); //Try to obtain the read lock configured by the current request (to avoid read-write conflict) final String requestIp = RequestUtil.getRemoteIp(request); //ip address of the requester boolean isBeta = false; //Lockresult > 0 indicates that the cacheitem (that is, the configuration item of the cache) is not empty and has been locked for reading, which means that the cached data cannot be deleted. //lockResult=0 indicates that the cacheItem is empty and no read lock is required //lockResult=01 indicates that locking failed and there is a conflict. //The following if is to deal with these three cases. if (lockResult > 0) { // LockResult > 0 means cacheItem is not null and other thread can`t delete this cacheItem FileInputStream fis = null; try { String md5 = Constants.NULL; long lastModified = 0L; //Get the CacheItem from the local cache according to the groupKey CacheItem cacheItem = ConfigCacheService.getContentCache(groupKey); //Determine whether it is a beta release, that is, a test version if (cacheItem.isBeta() && cacheItem.getIps4Beta().contains(clientIp)) { isBeta = true; } //Gets the type of configuration file final String configType = (null != cacheItem.getType()) ? cacheItem.getType() : FileTypeEnum.TEXT.getFileType(); response.setHeader("Config-Type", configType); //Returns an enumerated object of a file type FileTypeEnum fileTypeEnum = FileTypeEnum.getFileTypeEnumByFileExtensionOrFileType(configType); String contentTypeHeader = fileTypeEnum.getContentType(); response.setHeader(HttpHeaderConsts.CONTENT_TYPE, contentTypeHeader); File file = null; ConfigInfoBase configInfoBase = null; PrintWriter out = null; if (isBeta) { //In case of test configuration md5 = cacheItem.getMd54Beta(); lastModified = cacheItem.getLastModifiedTs4Beta(); if (PropertyUtil.isDirectRead()) { configInfoBase = persistService.findConfigInfo4Beta(dataId, group, tenant); } else { file = DiskUtil.targetBetaFile(dataId, group, tenant); //Get the File from the disk and get a complete File } response.setHeader("isBeta", "true"); } else { if (StringUtils.isBlank(tag)) { //Judge whether the tag tag is empty. The tag corresponds to the tag option in the nacos configuration center if (isUseTag(cacheItem, autoTag)) { if (cacheItem.tagMd5 != null) { md5 = cacheItem.tagMd5.get(autoTag); } if (cacheItem.tagLastModifiedTs != null) { lastModified = cacheItem.tagLastModifiedTs.get(autoTag); } if (PropertyUtil.isDirectRead()) { configInfoBase = persistService.findConfigInfo4Tag(dataId, group, tenant, autoTag); } else { file = DiskUtil.targetTagFile(dataId, group, tenant, autoTag); } response.setHeader("Vipserver-Tag", URLEncoder.encode(autoTag, StandardCharsets.UTF_8.displayName())); } else {//Directly follow this logic (the tag attribute will not be configured by default) md5 = cacheItem.getMd5(); //Get cached md5 lastModified = cacheItem.getLastModifiedTs(); //Get last update time if (PropertyUtil.isDirectRead()) { //Judge whether it is a standalone mode and uses the derby database. If so, load data from the derby database configInfoBase = persistService.findConfigInfo(dataId, group, tenant); } else { //Otherwise, in case of database or cluster mode, get the file from the local disk first file = DiskUtil.targetFile(dataId, group, tenant); } //If the local disk file is empty and configinfbase is empty, the configuration data does not exist and null is returned directly if (configInfoBase == null && fileNotExist(file)) { // FIXME CacheItem // No longer exists. It is impossible to simply calculate the push delayed. Here, simply record it as - 1. ConfigTraceService.logPullEvent(dataId, group, tenant, requestIpApp, -1, ConfigTraceService.PULL_EVENT_NOTFOUND, -1, requestIp); // pullLog.info("[client-get] clientIp={}, {}, // no data", // new Object[]{clientIp, groupKey}); response.setStatus(HttpServletResponse.SC_NOT_FOUND); response.getWriter().println("config data not exist"); return HttpServletResponse.SC_NOT_FOUND + ""; } } } else {//If the tag is not empty, it indicates that the tag tag is set in the configuration file if (cacheItem.tagMd5 != null) { md5 = cacheItem.tagMd5.get(tag); } if (cacheItem.tagLastModifiedTs != null) { Long lm = cacheItem.tagLastModifiedTs.get(tag); if (lm != null) { lastModified = lm; } } if (PropertyUtil.isDirectRead()) { configInfoBase = persistService.findConfigInfo4Tag(dataId, group, tenant, tag); } else { file = DiskUtil.targetTagFile(dataId, group, tenant, tag); } if (configInfoBase == null && fileNotExist(file)) { // FIXME CacheItem // No longer exists. It is impossible to simply calculate the push delayed. Here, simply record it as - 1. ConfigTraceService.logPullEvent(dataId, group, tenant, requestIpApp, -1, ConfigTraceService.PULL_EVENT_NOTFOUND, -1, requestIp); // pullLog.info("[client-get] clientIp={}, {}, // no data", // new Object[]{clientIp, groupKey}); response.setStatus(HttpServletResponse.SC_NOT_FOUND); response.getWriter().println("config data not exist"); return HttpServletResponse.SC_NOT_FOUND + ""; } } } //Set the obtained data result to the response and return response.setHeader(Constants.CONTENT_MD5, md5); // Disable cache. response.setHeader("Pragma", "no-cache"); response.setDateHeader("Expires", 0); response.setHeader("Cache-Control", "no-cache,no-store"); if (PropertyUtil.isDirectRead()) { response.setDateHeader("Last-Modified", lastModified); } else { fis = new FileInputStream(file); response.setDateHeader("Last-Modified", file.lastModified()); } //If it is in stand-alone mode, write the data directly back to the client if (PropertyUtil.isDirectRead()) { out = response.getWriter(); out.print(configInfoBase.getContent()); out.flush(); out.close(); } else {//Otherwise, through trasferTo fis.getChannel() .transferTo(0L, fis.getChannel().size(), Channels.newChannel(response.getOutputStream())); } LogUtil.PULL_CHECK_LOG.warn("{}|{}|{}|{}", groupKey, requestIp, md5, TimeUtils.getCurrentTimeStr()); final long delayed = System.currentTimeMillis() - lastModified; // TODO distinguish pull-get && push-get /* Otherwise, delayed cannot be used as the basis of push delay directly, because the delayed value of active get requests is very large. */ ConfigTraceService.logPullEvent(dataId, group, tenant, requestIpApp, lastModified, ConfigTraceService.PULL_EVENT_OK, delayed, requestIp); } finally { releaseConfigReadLock(groupKey); //Release lock IoUtils.closeQuietly(fis); } } else if (lockResult == 0) { //Description cache is empty, // FIXME CacheItem No longer exists. It is impossible to simply calculate the push delayed. Here, simply record it as - 1. ConfigTraceService .logPullEvent(dataId, group, tenant, requestIpApp, -1, ConfigTraceService.PULL_EVENT_NOTFOUND, -1, requestIp); response.setStatus(HttpServletResponse.SC_NOT_FOUND); response.getWriter().println("config data not exist"); return HttpServletResponse.SC_NOT_FOUND + ""; } else {// PULL_LOG.info("[client-get] clientIp={}, {}, get data during dump", clientIp, groupKey); response.setStatus(HttpServletResponse.SC_CONFLICT); response.getWriter().println("requested file is being modified, please try later."); return HttpServletResponse.SC_CONFLICT + ""; } return HttpServletResponse.SC_OK + ""; }
persistService.findConfigInfo
Getting data content from derby database is a basic data query operation.
@Override public ConfigInfo findConfigInfo(final String dataId, final String group, final String tenant) { final String tenantTmp = StringUtils.isBlank(tenant) ? StringUtils.EMPTY : tenant; final String sql = "SELECT ID,data_id,group_id,tenant_id,app_name,content,md5,type FROM config_info " + " WHERE data_id=? AND group_id=? AND tenant_id=?"; final Object[] args = new Object[] {dataId, group, tenantTmp}; return databaseOperate.queryOne(sql, args, CONFIG_INFO_ROW_MAPPER); }
DiskUtil.targetFile
Get the target file from the disk directory and directly find the file in the specified directory according to dataId/group/tenant
public static File targetFile(String dataId, String group, String tenant) { File file = null; if (StringUtils.isBlank(tenant)) { file = new File(EnvUtil.getNacosHome(), BASE_DIR); } else { file = new File(EnvUtil.getNacosHome(), TENANT_BASE_DIR); file = new File(file, tenant); } file = new File(file, group); file = new File(file, dataId); return file; }
So far, NacosPropertySourceLocator has completed the dynamic configuration acquisition from Nacos Server and cached locally, so as to realize the ability of Nacos dynamic configuration acquisition!
Copyright notice: unless otherwise stated, all articles on this blog adopt CC BY-NC-SA 4.0 license agreement. Reprint please indicate from Mic to take you to learn architecture!
If this article is helpful to you, please pay attention and praise. Your persistence is the driving force of my continuous creation. Welcome to WeChat public official account for more dry cargo.