大家好,如果您还对智能解析网站源码分享不太了解,没有关系,今天就由本站为大家分享智能解析网站源码分享的知识,包括什么鬼智能解析的问题都会给大家分析到,还望可以解决大家的问题,下面我们就开始吧!
一、概述
ConfigService:
提供配置读取、推送等功能,Apollo客户端会调用configservice
AdminService:
提供配置修改、发布等功能,ApolloPortal(也就是我们使用的管理界面)增删改查会调用adminservice
ConfigService和AdminService需将自己注册到Eureka集群中,在Eureka之上又部署了一层MetaServer用于封装Eureka的服务发现接口。
Client:
client端通过域名访问MetaServer获取ConfigService服务列表(IP+Port),然后通过IP+Port访问服务。
Portal:
portal通过域名访问MetaServer获取AdminService服务列表(IP+Port),然后通过IP+Port访问服务。
为了简化部署,通常会将ConfigService、Eureka和MetaServer三者部署在同一个JVM进程中。
二、源码分析
查看apollo-client的META-INF/spring.factories文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\n//自动装配类:ApolloAutoConfiguration\ncom.ctrip.framework.apollo.spring.boot.ApolloAutoConfiguration\norg.springframework.context.ApplicationContextInitializer=\\\n//初始化器:ApolloApplicationContextInitializer\ncom.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer\norg.springframework.boot.env.EnvironmentPostProcessor=\\\ncom.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer
ApolloAutoConfiguration类:
@Configuration\n//条件注解:apollo.bootstrap.enabled\n@ConditionalOnProperty({&34;})\n@ConditionalOnMissingBean({PropertySourcesProcessor.class})\npublicclassApolloAutoConfiguration{\npublicApolloAutoConfiguration(){\n}\n\n//如果容器中不存在PropertySourcesProcessor类型的bean,则会注入ConfigPropertySourcesProcessor\n@Bean\npublicConfigPropertySourcesProcessorconfigPropertySourcesProcessor(){\nreturnnewConfigPropertySourcesProcessor();\n}\n}
ConfigPropertySourcesProcessor(继承了BeanFactoryPostProcessor类):
publicclassConfigPropertySourcesProcessorextendsPropertySourcesProcessorimplementsBeanDefinitionRegistryPostProcessor{\nprivateConfigPropertySourcesProcessorHelperhelper=(ConfigPropertySourcesProcessorHelper)ServiceBootstrap.loadPrimary(ConfigPropertySourcesProcessorHelper.class);\npublicConfigPropertySourcesProcessor(){\n}\n//调用父类方法,注册bean定义(beanDefinition)\npublicvoidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistryregistry)throwsBeansException{\nthis.helper.postProcessBeanDefinitionRegistry(registry);\n}\n}\n\npublicclassDefaultConfigPropertySourcesProcessorHelperimplementsConfigPropertySourcesProcessorHelper{\npublicDefaultConfigPropertySourcesProcessorHelper(){\n}\n\npublicvoidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistryregistry)throwsBeansException{\nMap<String,Object>propertySourcesPlaceholderPropertyValues=newHashMap();\npropertySourcesPlaceholderPropertyValues.put(&34;,0);\n//解析占位符:@Vlaue(${***:***}),从PropertySource中找到对应的属性值,替换掉占位符\nBeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry,PropertySourcesPlaceholderConfigurer.class.getName(),PropertySourcesPlaceholderConfigurer.class,propertySourcesPlaceholderPropertyValues);\n//解析@ApolloConfig、ApolloConfigChangeListener等注解\nBeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry,ApolloAnnotationProcessor.class.getName(),ApolloAnnotationProcessor.class);\n//解析@Value注解标注的类成员变量和方法\nBeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry,SpringValueProcessor.class.getName(),SpringValueProcessor.class);\n//解析@ApolloJsonValue注解\nBeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry,ApolloJsonValueProcessor.class.getName(),ApolloJsonValueProcessor.class);\nthis.processSpringValueDefinition(registry);\n}\n\nprivatevoidprocessSpringValueDefinition(BeanDefinitionRegistryregistry){\nSpringValueDefinitionProcessorspringValueDefinitionProcessor=newSpringValueDefinitionProcessor();\nspringValueDefinitionProcessor.postProcessBeanDefinitionRegistry(registry);\n}\n\npublicintgetOrder(){\nreturn2147483647;\n}\n}
ApolloApplicationContextInitializer:
publicclassApolloApplicationContextInitializerimplementsApplicationContextInitializer<ConfigurableApplicationContext>,EnvironmentPostProcessor,Ordered{\npublicstaticfinalintDEFAULT_ORDER=0;\nprivatestaticfinalLoggerlogger=LoggerFactory.getLogger(ApolloApplicationContextInitializer.class);\nprivatestaticfinalSplitterNAMESPACE_SPLITTER=Splitter.on(&34;).omitEmptyStrings().trimResults();\nprivatestaticfinalString[]APOLLO_SYSTEM_PROPERTIES=newString[]{&34;,&34;,&34;,&34;,&34;,&34;,&34;,&34;,&34;};\nprivatefinalConfigPropertySourceFactoryconfigPropertySourceFactory=(ConfigPropertySourceFactory)SpringInjector.getInstance(ConfigPropertySourceFactory.class);\nprivateintorder=0;\n\npublicApolloApplicationContextInitializer(){\n}\n\npublicvoidinitialize(ConfigurableApplicationContextcontext){\nConfigurableEnvironmentenvironment=context.getEnvironment();\n//可通过apollo.bootstrap.enabled配置项,设置是否需要初始化apollo配置\nif(!(Boolean)environment.getProperty(&34;,Boolean.class,false)){\nlogger.debug(&34;,context,&34;);\n}else{\nlogger.debug(&34;,context);\n//开启了则进行初始化操作\nthis.initialize(environment);\n}\n}\n\n\t//初始化apollo配置\nprotectedvoidinitialize(ConfigurableEnvironmentenvironment){\nif(!environment.getPropertySources().contains(&34;)){\n//获取我们配置的所有的apollo命名空间:apollo.bootstrap.namespaces,默认是application\nStringnamespaces=environment.getProperty(&34;,&34;);\nlogger.debug(&34;,namespaces);\nList<String>namespaceList=NAMESPACE_SPLITTER.splitToList(namespaces);\nCompositePropertySourcecomposite=newCompositePropertySource(&34;);\nIteratorvar5=namespaceList.iterator();\n\t//遍历所有的命名空间\nwhile(var5.hasNext()){\nStringnamespace=(String)var5.next();\n//每一个命名空间都对应一个Config【ConfigService.getConfig重要方法】\nConfigconfig=ConfigService.getConfig(namespace);\n//构建ConfigPropertySource(继承了PropertySource)对象,添加到CompositePropertySource中\ncomposite.addPropertySource(this.configPropertySourceFactory.getConfigPropertySource(namespace,config));\n}\n//添加到环境变量中\nenvironment.getPropertySources().addFirst(composite);\n}\n}\n\nvoidinitializeSystemProperty(ConfigurableEnvironmentenvironment){\nString[]var2=APOLLO_SYSTEM_PROPERTIES;\nintvar3=var2.length;\n\nfor(intvar4=0;var4<var3;++var4){\nStringpropertyName=var2[var4];\nthis.fillSystemPropertyFromEnvironment(environment,propertyName);\n}\n}\n\nprivatevoidfillSystemPropertyFromEnvironment(ConfigurableEnvironmentenvironment,StringpropertyName){\nif(System.getProperty(propertyName)==null){\nStringpropertyValue=environment.getProperty(propertyName);\nif(!Strings.isNullOrEmpty(propertyValue)){\nSystem.setProperty(propertyName,propertyValue);\n}\n}\n}\n\n//由于继承了EnvironmentPostProcessor接口,所以会先执行此方法,然后再执行上面的方法\npublicvoidpostProcessEnvironment(ConfigurableEnvironmentconfigurableEnvironment,SpringApplicationspringApplication){\n//初始化系统属性:&34;,&34;,&34;,&34;,&34;,&34;,&34;,&34;,&34;\nthis.initializeSystemProperty(configurableEnvironment);\n//apollo.bootstrap.eagerLoad.enabled:是否允许项目启动时加载apollo配置\n//apollo.bootstrap.enabled:是否允许加载apollo\n//都为true,则调用initialize方法进行初始化\n\tBooleaneagerLoadEnabled=(Boolean)configurableEnvironment.getProperty(&34;,Boolean.class,false);\nif(eagerLoadEnabled){\nBooleanbootstrapEnabled=(Boolean)configurableEnvironment.getProperty(&34;,Boolean.class,false);\nif(bootstrapEnabled){\nthis.initialize(configurableEnvironment);\n}\n}\n}\n}
接下来重点看下ConfigService.getConfig方法:
publicstaticConfiggetConfig(Stringnamespace){\nreturns_instance.getManager().getConfig(namespace);\n}\n\nprivateConfigManagergetManager(){\n//使用DCL以防重复实例化\nif(this.m_configManager==null){\nsynchronized(this){\nif(this.m_configManager==null){\n//采用ApolloInjector获取ConfigManager实例\nthis.m_configManager=(ConfigManager)ApolloInjector.getInstance(ConfigManager.class);\n}\n}\n}\nreturnthis.m_configManager;\n}\n\npublicstatic<T>TgetInstance(Class<T>clazz){\ntry{\nreturngetInjector().getInstance(clazz);\n}catch(Throwablevar2){\nTracer.logError(var2);\nthrownewApolloConfigException(String.format(&34;,clazz.getName()),var2);\n}\n}\n\nprivatestaticInjectorgetInjector(){\nif(s_injector==null){\nsynchronized(lock){\nif(s_injector==null){\ntry{\n//采用spi机制,默认获取到是:DefaultInjector\ns_injector=(Injector)ServiceBootstrap.loadFirst(Injector.class);\n}catch(Throwablevar4){\nApolloConfigExceptionexception=newApolloConfigException(&34;,var4);\nTracer.logError(exception);\nthrowexception;\n}\n}\n}\n}
接着看getConfig方法
publicConfiggetConfig(Stringnamespace){\nConfigconfig=(Config)this.m_configs.get(namespace);\nif(config==null){\nsynchronized(this){\nconfig=(Config)this.m_configs.get(namespace);\nif(config==null){\n//最终也是同上,采用spi机制,默认获取到的是:DefaultConfigFactory\nConfigFactoryfactory=this.m_factoryManager.getFactory(namespace);\n//调用DefaultConfigFactory.create方法创建Config对象\nconfig=factory.create(namespace);\nthis.m_configs.put(namespace,config);\n}\n}\n}\nreturnconfig;\n}\n\npublicConfigcreate(Stringnamespace){\n//获取本地配置缓存文件的格式(本地、远程)—【继续往下分析】\nConfigFileFormatformat=this.determineFileFormat(namespace);\nreturnConfigFileFormat.isPropertiesCompatible(format)\n?newDefaultConfig(namespace,this.createPropertiesCompatibleFileConfigRepository(namespace,format))\n\t//我们这里走的是else分支\n:newDefaultConfig(namespace,this.createLocalConfigRepository(namespace));\n}\n\n//createLocalConfigRepository\nLocalFileConfigRepositorycreateLocalConfigRepository(Stringnamespace){\n\t\t//local模式很少使用,这里我们使用的远程模式\nif(this.m_configUtil.isInLocalMode()){\nlogger.warn(&39;tpullconfigsfromremoteserverfornamespace{}!====&34;ApolloConfigException&34;Syncconfigfailed,willretry.Repository{},reason:{}&34;Apollo.ConfigService&34;syncRemoteConfig&34;RemoteConfigrefreshed!&34;Apollo.Client.Configs.%s&34;0&34;Failedtoinvokerepositorychangelistener{}&onChange(配置热发布):
publicvoidonChange(ConfigChangeEventchangeEvent){\n\t\t\t//从变更事件中获取变更的key(比如我们配置的:maxSize参数)\nSet<String>keys=changeEvent.changedKeys();\nif(!CollectionUtils.isEmpty(keys)){\nIteratorvar3=keys.iterator();\nwhile(true){\nCollectiontargetValues;\ndo{\ndo{\nif(!var3.hasNext()){\nreturn;\n}\nStringkey=(String)var3.next();\n\t//根据key从springValueRegistry中获取SpringValue\ntargetValues=this.springValueRegistry.get(this.beanFactory,key);\n}while(targetValues==null);\n}while(targetValues.isEmpty());\nIteratorvar6=targetValues.iterator();\nwhile(var6.hasNext()){\nSpringValueval=(SpringValue)var6.next();\n\t//最终通过反射修改属性值,从而实现了配置热发布\nthis.updateSpringValue(val);\n}\n}\n}\n}\n\nprivatevoidupdateSpringValue(SpringValuespringValue){\ntry{\nObjectvalue=this.resolvePropertyValue(springValue);\n\t//通过反射更新属性值\nspringValue.update(value);\nlogger.info(&34;,value,springValue);\n}catch(Throwablevar3){\nlogger.error(&34;,springValue.toString(),var3);\n}\n}\n\npublicvoidupdate(ObjectnewVal)throwsIllegalAccessException,InvocationTargetException{\nif(this.isField()){\nthis.injectField(newVal);\n}else{\nthis.injectMethod(newVal);\n}\n}\n\nprivatevoidinjectField(ObjectnewVal)throwsIllegalAccessException{\nObjectbean=this.beanRef.get();\nif(bean!=null){\nbooleanaccessible=this.field.isAccessible();\nthis.field.setAccessible(true);\nthis.field.set(bean,newVal);\nthis.field.setAccessible(accessible);\n}\n}
schedulePeriodicRefresh(每5分钟轮询apollo配置):
privatevoidschedulePeriodicRefresh(){\nlogger.debug(&34;,this.m_configUtil.getRefreshInterval(),this.m_configUtil.getRefreshIntervalTimeUnit());\nm_executorService.scheduleAtFixedRate(newRunnable(){\npublicvoidrun(){\nTracer.logEvent(&34;,String.format(&34;,RemoteConfigRepository.this.m_namespace));\nRemoteConfigRepository.logger.debug(&34;,RemoteConfigRepository.this.m_namespace);\n//同步apollo配置和上述一样\n\t\t\tRemoteConfigRepository.this.trySync();\nTracer.logEvent(&34;,Apollo.VERSION);\n}\n},(long)this.m_configUtil.getRefreshInterval(),(long)this.m_configUtil.getRefreshInterval(),this.m_configUtil.getRefreshIntervalTimeUnit());\n}
scheduleLongPollingRefresh(长轮询):
privatevoidscheduleLongPollingRefresh(){\nthis.remoteConfigLongPollService.submit(this.m_namespace,this);\n}\n\npublicbooleansubmit(Stringnamespace,RemoteConfigRepositoryremoteConfigRepository){\nbooleanadded=this.m_longPollNamespaces.put(namespace,remoteConfigRepository);\nthis.m_notifications.putIfAbsent(namespace,-1L);\nif(!this.m_longPollStarted.get()){\n\t//开启长轮询\nthis.startLongPolling();\n}\nreturnadded;\n}\n\nprivatevoidstartLongPolling(){\n\t\t\t//cas以防多次启动\nif(this.m_longPollStarted.compareAndSet(false,true)){\ntry{\n\t//从缓存中获取apollo基础信息:appId、secret、appVersion、cluster、dataCenter等\nfinalStringappId=this.m_configUtil.getAppId();\nStringappVersion=this.m_configUtil.getAppVersion();\nfinalStringcluster=this.m_configUtil.getCluster();\nfinalStringdataCenter=this.m_configUtil.getDataCenter();\nfinalStringsecret=this.m_configUtil.getAccessKeySecret();\n\t//获得长轮询任务初始化延迟时间(默认2秒)\nfinallonglongPollingInitialDelayInMills=this.m_configUtil.getLongPollingInitialDelayInMills();\nthis.m_longPollingService.submit(newRunnable(){\npublicvoidrun(){\n\t\t\t//初始等待,默认休眠2秒\nif(longPollingInitialDelayInMills>0L){\ntry{\nRemoteConfigLongPollService.logger.debug(&34;,longPollingInitialDelayInMills);\nTimeUnit.MILLISECONDS.sleep(longPollingInitialDelayInMills);\n}catch(InterruptedExceptionvar2){\n}\n}\n\t\t\t//执行长轮询\nRemoteConfigLongPollService.this.doLongPollingRefresh(appId,cluster,dataCenter,secret);\n}\n});\n}catch(Throwablevar8){\nthis.m_longPollStarted.set(false);\nApolloConfigExceptionexception=newApolloConfigException(&34;,var8);\nTracer.logError(exception);\nlogger.warn(ExceptionUtil.getDetailMessage(exception));\n}\n}\n}
doLongPollingRefresh(执行长轮询):
privatevoiddoLongPollingRefresh(StringappId,Stringcluster,StringdataCenter,Stringsecret){\nRandomrandom=newRandom();\nServiceDTOlastServiceDto=null;\nwhile(!this.m_longPollingStopped.get()&&!Thread.currentThread().isInterrupted()){\n\t//限流,每5秒执行一次长轮询\nif(!this.m_longPollRateLimiter.tryAcquire(5L,TimeUnit.SECONDS)){\ntry{\nTimeUnit.SECONDS.sleep(5L);\n}catch(InterruptedExceptionvar21){\n}\n}\nTransactiontransaction=Tracer.newTransaction(&34;,&34;);\nStringurl=null;\ntry{\nif(lastServiceDto==null){\n\t//获取configservice服务列表\nList<ServiceDTO>configServices=this.getConfigServices();\nlastServiceDto=(ServiceDTO)configServices.get(random.nextInt(configServices.size()));\n}\n\t//组装URL\nurl=this.assembleLongPollRefreshUrl(lastServiceDto.getHomepageUrl(),appId,cluster,dataCenter,this.m_notifications);\nlogger.debug(&34;,url);\nHttpRequestrequest=newHttpRequest(url);\nrequest.setReadTimeout(90000);\nif(!StringUtils.isBlank(secret)){\nMap<String,String>headers=Signature.buildHttpHeaders(url,appId,secret);\nrequest.setHeaders(headers);\n}\ntransaction.addData(&34;,url);\n\t//发起http请求\nHttpResponse<List<ApolloConfigNotification>>response=this.m_httpUtil.doGet(request,this.m_responseType);\nlogger.debug(&34;,response.getStatusCode(),url);\n//200:代表存在配置更新,更新本地缓存,然后再调用上面提到的trySync()方法更新远程配置\nif(response.getStatusCode()==200&&response.getBody()!=null){\nthis.updateNotifications((List)response.getBody());\nthis.updateRemoteNotifications((List)response.getBody());\ntransaction.addData(&34;,((List)response.getBody()).toString());\nthis.notify(lastServiceDto,(List)response.getBody());\n}\n\t//304:代表无配置更新,重置连接的ConfigService的地址\n\t//下次请求不同的ConfigService,以实现负载均衡\nif(response.getStatusCode()==304&&random.nextBoolean()){\nlastServiceDto=null;\n}\nthis.m_longPollFailSchedulePolicyInSecond.success();\ntransaction.addData(&34;,response.getStatusCode());\ntransaction.setStatus(&34;);\n}catch(Throwablevar19){\nlastServiceDto=null;\nTracer.logEvent(&34;,ExceptionUtil.getDetailMessage(var19));\ntransaction.setStatus(var19);\nlongsleepTimeInSecond=this.m_longPollFailSchedulePolicyInSecond.fail();\nlogger.warn(&34;,newObject[]{sleepTimeInSecond,appId,cluster,this.assembleNamespaces(),url,ExceptionUtil.getDetailMessage(var19)});\ntry{\nTimeUnit.SECONDS.sleep(sleepTimeInSecond);\n}catch(InterruptedExceptionvar18){\n}\n}finally{\ntransaction.complete();\n}\n}\n}
最后看下@EnableApolloConfig注解:
@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.TYPE})\n@Documented\n@Import({ApolloConfigRegistrar.class})\npublic@interfaceEnableApolloConfig{\nString[]value()default{&34;};\nintorder()default2147483647;\n}
ApolloConfigRegistrar:
publicclassApolloConfigRegistrarimplementsImportBeanDefinitionRegistrar{\nprivateApolloConfigRegistrarHelperhelper=(ApolloConfigRegistrarHelper)ServiceBootstrap.loadPrimary(ApolloConfigRegistrarHelper.class);\npublicApolloConfigRegistrar(){\n}\npublicvoidregisterBeanDefinitions(AnnotationMetadataimportingClassMetadata,BeanDefinitionRegistryregistry){\nthis.helper.registerBeanDefinitions(importingClassMetadata,registry);\n}\n}\n\n//注册bean定义,上面已经介绍过这几个类了,此处不再阐述\npublicvoidregisterBeanDefinitions(AnnotationMetadataimportingClassMetadata,BeanDefinitionRegistryregistry){\nAnnotationAttributesattributes=AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(EnableApolloConfig.class.getName()));\nString[]namespaces=attributes.getStringArray(&34;);\nintorder=(Integer)attributes.getNumber(&34;);\nPropertySourcesProcessor.addNamespaces(Lists.newArrayList(namespaces),order);\nMap<String,Object>propertySourcesPlaceholderPropertyValues=newHashMap();\npropertySourcesPlaceholderPropertyValues.put(&34;,0);\nBeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry,PropertySourcesPlaceholderConfigurer.class.getName(),PropertySourcesPlaceholderConfigurer.class,propertySourcesPlaceholderPropertyValues);\nBeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry,PropertySourcesProcessor.class.getName(),PropertySourcesProcessor.class);\nBeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry,ApolloAnnotationProcessor.class.getName(),ApolloAnnotationProcessor.class);\nBeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry,SpringValueProcessor.class.getName(),SpringValueProcessor.class);\nBeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry,SpringValueDefinitionProcessor.class.getName(),SpringValueDefinitionProcessor.class);\nBeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry,ApolloJsonValueProcessor.class.getName(),ApolloJsonValueProcessor.class);\n}
三、总结
Apollo通过spring的BeanPostProcessor、BeanFactoryPostProcessor、事件机制等扩展点,将我们配置的参数${***:***}注册到注册表springValueRegistry(SpringValue集合)中;当修改配置发布事件后,AutoUpdateConfigChangeListener的onChange(ConfigChangeEventchangeEvent)方法将会被调用,最终通过反射机制,更新bean的属性信息,从而实现热发布功能。最后再回顾下三个重要的方法:
//从远程同步apollo配置,然后保存到内存中,同时也会持久化到磁盘中\nthis.trySync();\n//开启定时任务,每隔5分钟刷新一次apollo配置\nthis.schedulePeriodicRefresh();\n//开启长轮询,负责长轮循ConfigServer变更通知\nthis.scheduleLongPollingRefresh();
好了,本文到此结束,如果可以帮助到大家,还望关注本站哦!
