微软存放位置在哪里
678
2022-05-30
9Nacos配置中心之加载配置客户端和服务端的处理
一 客户端配置中心之加载配置
prepareContext()方法
applyInitializers()方法
PropertySourceBootstrapConfiguration的initialize()方法
NacosPropertySourceLocator的locate()方法
loadNacosData()方法
ClientWork的getServerConfig()方法
9Nacos配置中心之加载配置客户端和服务端的处理
一 客户端配置中心之加载配置
prepareContext()方法
applyInitializers()方法
PropertySourceBootstrapConfiguration的initialize()方法
NacosPropertySourceLocator的locate()方法
loadNacosData()方法
ClientWork的getServerConfig()方法
二 服务端/v1/cs/configs接口的处理
总结
9Nacos配置中心之加载配置客户端和服务端的处理
一 客户端配置中心之加载配置
我们接着上个文章说的,Springboot启动的时候调用prep在reEnvironment()进行环境准备,
prepareEnvironment()进行环境准备,在启动类执行完prepareEnvironment后,执行prepareContext进行刷新应用上下文件的准备
代码如下:
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection
我们看一下prepareContext()准备上下文方法做了什么
prepareContext()方法
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment); postProcessApplicationContext(context); applyInitializers(context); listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } // Load the sources Set
调用applyInitializers()方法
注册打印banner图的单例bean
加载资源
我们再看一下applyInitializers()方法是做什么的
applyInitializers()方法
@SuppressWarnings({ "rawtypes", "unchecked" }) protected void applyInitializers(ConfigurableApplicationContext context) { for (ApplicationContextInitializer initializer : getInitializers()) { Class> requiredType = GenericTypeResolver.resolveTypeArgument( initializer.getClass(), ApplicationContextInitializer.class); Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); initializer.initialize(context); } }
PropertySourceBootstrapConfiguration实现了ApplicationContextInitializer接口,所以会调用PropertySourceBootstrapConfiguration的initialize()方法
PropertySourceBootstrapConfiguration的initialize()方法
@Override public void initialize(ConfigurableApplicationContext applicationContext) { CompositePropertySource composite = new CompositePropertySource( BOOTSTRAP_PROPERTY_SOURCE_NAME); AnnotationAwareOrderComparator.sort(this.propertySourceLocators); boolean empty = true; ConfigurableEnvironment environment = applicationContext.getEnvironment(); for (PropertySourceLocator locator : this.propertySourceLocators) { PropertySource> source = null; //加载 source = locator.locate(environment); if (source == null) { continue; } logger.info("Located property source: " + source); composite.addPropertySource(source); empty = false; } if (!empty) { MutablePropertySources propertySources = environment.getPropertySources(); String logConfig = environment.resolvePlaceholders("${logging.config:}"); LogFile logFile = LogFile.get(environment); if (propertySources.contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) { propertySources.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME); } insertPropertySources(propertySources, composite); reinitializeLoggingSystem(environment, logConfig, logFile); setLogLevels(applicationContext, environment); handleIncludedProfiles(environment); } }
locator.locate(environment)方法会调用NacosPropertySourceLocator的locate方法,这就是加载配置的关键代码了
NacosPropertySourceLocator的locate()方法
@Override public PropertySource> locate(Environment env) { ConfigService configService = nacosConfigProperties.configServiceInstance(); if (null == configService) { log.warn("no instance of config service found, can't 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; }
初始化ConfigService对象,ConfigService是Nacos客户端提供的用于访问实现配置中心基本操作的类
如果为空打印支持没有ConfigService实例,不能加载配置,返回空
如果不为空,按照顺序分别加载共享配置、扩展配置、应用名称对应的配置。
进入loadApplicationConfiguration-》loadNacosDataIfPresent-》loadNacosPropertySource-》build-》loadNacosData
loadNacosData()方法
private Properties loadNacosData(String dataId, String group, String fileExtension) { String data = null; try { 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 EMPTY_PROPERTIES; } log.info(String.format( "Loading nacos data, dataId: '%s', group: '%s', data: %s", dataId, group, data)); Properties properties = NacosDataParserHandler.getInstance() .parseNacosData(data, fileExtension); return properties == null ? EMPTY_PROPERTIES : properties; } 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 EMPTY_PROPERTIES; }
configService.getConfig方法从Nacos配置中心上加载配置进行填充
private String getConfigInner(String tenant, String dataId, String group, long timeoutMs) throws NacosException { group = null2defaultGroup(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); configFilterChainManager.doFilter(null, cr); content = cr.getContent(); return content; } try { content = worker.getServerConfig(dataId, group, tenant, timeoutMs); cr.setContent(content); 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); configFilterChainManager.doFilter(null, cr); content = cr.getContent(); return content; }
方法中优先加载本地的配置,如果不为空就返回结果,否则这里又会调用ClientWork的getServerConfig()方法获取内容然后返回结果
ClientWork的getServerConfig()方法
public String getServerConfig(String dataId, String group, String tenant, long readTimeout) throws NacosException { if (StringUtils.isBlank(group)) { group = Constants.DEFAULT_GROUP; } HttpResult result = null; try { List
现在水落石出了,这里调用客户端向服务端发送请求,agent.httpGet()发起请求,请求路径:/v1/cs/configs
二 服务端/v1/cs/configs接口的处理
服务端在nacos.config包下,ConfigController类的getConfig()方法
@GetMapping @Secured(action = ActionTypes.READ, signType = SignType.CONFIG) 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); // check params ParamUtils.checkParam(dataId, group, "datumId", "content"); ParamUtils.checkParam(tag); final String clientIp = RequestUtil.getRemoteIp(request); String isNotify = request.getHeader("notify"); inner.doGetConfig(request, response, dataId, group, tenant, tag, isNotify, clientIp); }
调用了ConfigServletInner的doGetConfig()方法,调用tryConfigReadLock()方法加入读锁,查看缓存中有没有nacos中配置的key 有的话就加锁成功了,加锁成功后调用ConfigCacheService.getContentCache()获取CacheItem实例,然后判断,然后根据配置信息等选择从数据库取数据还是获取本地文件,然后返回文件内容返回给客户端
总结
启动类执行完prepareEnvironment后,执行prepareContext进行刷新应用上下文件的准备,调用applyInitializers,调用NacosPropertySourceLocator的locate方法,初始化ConfigService对象,按照顺序分别加载共享配置、扩展配置、应用名称对应的配置,进入loadNacosData方法,然后configService.getConfig方法从Nacos配置中心上加载配置进行填充。
这就是nacos初始化的大体流程,如果我们在工作中遇到获取nacos数据获取不到的时候,我们可以试着跟踪一下nacos加载数据的流程,分析问题,定位问题,及时解决。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。