Java Apollo是如何实现配置更新的
这篇文档主要关注下配置修改后对应的Java对象是如何更新,并不关注整体的配置改动流程
所有代码都来自apollo-client项目
更新流程
在Apollo控制台进行配置修改并发布后,对应的client端拉取到更新后,会调用到com.ctrip.framework.apollo.spring.property.AutoUpdateConfigChangeListener#onChange方法
在调用onChange会收到对应的修改的配置信息ConfigChangeEvent,其中包含改动的key和value,则改动流程如下:
- 根据改动的配置的key从springValueRegistry找到对应的关联到这个key的SpringBean信息,如果找不到则不处理
- 根据找到的SpringBean信息,进行对应关联配置的更新
在第二步中会判断关联配置是用过属性关联还是方法进行关联的,代码如下
publicvoidupdate(ObjectnewVal)throwsIllegalAccessException,InvocationTargetException{ if(isField()){ injectField(newVal); }else{ injectMethod(newVal); } }
在上面的问题中,还有两个问题存疑
- 如何通过key找到对应的SpringBean信息
- 如何将Apollo的配置值转换为Spring的识别的值
publicclassAutoUpdateConfigChangeListenerimplementsConfigChangeListener{ privatestaticfinalLoggerlogger=LoggerFactory.getLogger(AutoUpdateConfigChangeListener.class); privatefinalbooleantypeConverterHasConvertIfNecessaryWithFieldParameter; privatefinalEnvironmentenvironment; privatefinalConfigurableBeanFactorybeanFactory; privatefinalTypeConvertertypeConverter; privatefinalPlaceholderHelperplaceholderHelper; privatefinalSpringValueRegistryspringValueRegistry; privatefinalGsongson; publicAutoUpdateConfigChangeListener(Environmentenvironment,ConfigurableListableBeanFactorybeanFactory){ this.typeConverterHasConvertIfNecessaryWithFieldParameter=testTypeConverterHasConvertIfNecessaryWithFieldParameter(); this.beanFactory=beanFactory; this.typeConverter=this.beanFactory.getTypeConverter(); this.environment=environment; this.placeholderHelper=SpringInjector.getInstance(PlaceholderHelper.class); this.springValueRegistry=SpringInjector.getInstance(SpringValueRegistry.class); this.gson=newGson(); } @Override publicvoidonChange(ConfigChangeEventchangeEvent){ Setkeys=changeEvent.changedKeys(); if(CollectionUtils.isEmpty(keys)){ return; } for(Stringkey:keys){ //1.checkwhetherthechangedkeyisrelevant Collection targetValues=springValueRegistry.get(beanFactory,key); if(targetValues==null||targetValues.isEmpty()){ continue; } //2.updatethevalue for(SpringValueval:targetValues){ updateSpringValue(val); } } } privatevoidupdateSpringValue(SpringValuespringValue){ try{ Objectvalue=resolvePropertyValue(springValue); springValue.update(value); logger.info("Autoupdateapollochangedvaluesuccessfully,newvalue:{},{}",value, springValue); }catch(Throwableex){ logger.error("Autoupdateapollochangedvaluefailed,{}",springValue.toString(),ex); } } /** *LogictransplantedfromDefaultListableBeanFactory *@seeorg.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency(org.springframework.beans.factory.config.DependencyDescriptor,java.lang.String,java.util.Set,org.springframework.beans.TypeConverter) */ privateObjectresolvePropertyValue(SpringValuespringValue){ //valuewillneverbenull,as@Valueand@ApolloJsonValuewillnotallowthat Objectvalue=placeholderHelper .resolvePropertyValue(beanFactory,springValue.getBeanName(),springValue.getPlaceholder()); if(springValue.isJson()){ value=parseJsonValue((String)value,springValue.getGenericType()); }else{ if(springValue.isField()){ //org.springframework.beans.TypeConverter#convertIfNecessary(java.lang.Object,java.lang.Class,java.lang.reflect.Field)isavailablefromSpring3.2.0+ if(typeConverterHasConvertIfNecessaryWithFieldParameter){ value=this.typeConverter .convertIfNecessary(value,springValue.getTargetType(),springValue.getField()); }else{ value=this.typeConverter.convertIfNecessary(value,springValue.getTargetType()); } }else{ value=this.typeConverter.convertIfNecessary(value,springValue.getTargetType(), springValue.getMethodParameter()); } } returnvalue; } privateObjectparseJsonValue(Stringjson,TypetargetType){ try{ returngson.fromJson(json,targetType); }catch(Throwableex){ logger.error("Parsingjson'{}'totype{}failed!",json,targetType,ex); throwex; } } privatebooleantestTypeConverterHasConvertIfNecessaryWithFieldParameter(){ try{ TypeConverter.class.getMethod("convertIfNecessary",Object.class,Class.class,Field.class); }catch(Throwableex){ returnfalse; } returntrue; } }
如何将配置key和SpringBean关联起来
在Spring常见配置包括2种
publicclassApiConfig{ //1.直接在Field是进行注入 @Value("${feifei.appId}") protectedStringappId; protectedStringpredUrl; //2.在方法上进行注入 @Value("${predUrl}") publicvoidsetPredUrl(StringpredUrl){ this.predUrl=predUrl; } }
在Apollo代码中,通过实现BeanPostProcessor接口来检测所有的SpringBean的创建过程,在SpringBean创建的过程中会调用对应的org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization和org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization方法。
Apollo通过在Bean生成过程中,检测Bean类中属性和方法是否存在@Value注解,如果存在,提出其中的key,其处理方法在processField和processMethod分别处理Field和Method中可能出现的@Value注解。如果存在注解则将对应的信息存到SpringValue对应springValueRegistry全局对象中,方便在其它地方可以直接获取。
在属性除了通过@Value注入,也可以用过xml进行配置,在这种情况通过processBeanPropertyValues方法来处理
通过两种处理方式就可以将key和对应的SpringBean信息关联起来
publicclassSpringValueProcessorextendsApolloProcessorimplementsBeanFactoryPostProcessor,BeanFactoryAware{ privatestaticfinalLoggerlogger=LoggerFactory.getLogger(SpringValueProcessor.class); privatefinalConfigUtilconfigUtil; privatefinalPlaceholderHelperplaceholderHelper; privatefinalSpringValueRegistryspringValueRegistry; privateBeanFactorybeanFactory; privateMultimapbeanName2SpringValueDefinitions; publicSpringValueProcessor(){ configUtil=ApolloInjector.getInstance(ConfigUtil.class); placeholderHelper=SpringInjector.getInstance(PlaceholderHelper.class); springValueRegistry=SpringInjector.getInstance(SpringValueRegistry.class); beanName2SpringValueDefinitions=LinkedListMultimap.create(); } @Override publicvoidpostProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory) throwsBeansException{ if(configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()&&beanFactoryinstanceofBeanDefinitionRegistry){ beanName2SpringValueDefinitions=SpringValueDefinitionProcessor .getBeanName2SpringValueDefinitions((BeanDefinitionRegistry)beanFactory); } } @Override publicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName) throwsBeansException{ if(configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()){ super.postProcessBeforeInitialization(bean,beanName); processBeanPropertyValues(bean,beanName); } returnbean; } @Override protectedvoidprocessField(Objectbean,StringbeanName,Fieldfield){ //register@Valueonfield Valuevalue=field.getAnnotation(Value.class); if(value==null){ return; } Set keys=placeholderHelper.extractPlaceholderKeys(value.value()); if(keys.isEmpty()){ return; } for(Stringkey:keys){ SpringValuespringValue=newSpringValue(key,value.value(),bean,beanName,field,false); springValueRegistry.register(beanFactory,key,springValue); logger.debug("Monitoring{}",springValue); } } @Override protectedvoidprocessMethod(Objectbean,StringbeanName,Methodmethod){ //register@Valueonmethod Valuevalue=method.getAnnotation(Value.class); if(value==null){ return; } //skipConfigurationbeanmethods if(method.getAnnotation(Bean.class)!=null){ return; } if(method.getParameterTypes().length!=1){ logger.error("Ignore@Valuesetter{}.{},expecting1parameter,actual{}parameters", bean.getClass().getName(),method.getName(),method.getParameterTypes().length); return; } Set keys=placeholderHelper.extractPlaceholderKeys(value.value()); if(keys.isEmpty()){ return; } for(Stringkey:keys){ SpringValuespringValue=newSpringValue(key,value.value(),bean,beanName,method,false); springValueRegistry.register(beanFactory,key,springValue); logger.info("Monitoring{}",springValue); } } privatevoidprocessBeanPropertyValues(Objectbean,StringbeanName){ Collection propertySpringValues=beanName2SpringValueDefinitions .get(beanName); if(propertySpringValues==null||propertySpringValues.isEmpty()){ return; } for(SpringValueDefinitiondefinition:propertySpringValues){ try{ PropertyDescriptorpd=BeanUtils .getPropertyDescriptor(bean.getClass(),definition.getPropertyName()); Methodmethod=pd.getWriteMethod(); if(method==null){ continue; } SpringValuespringValue=newSpringValue(definition.getKey(),definition.getPlaceholder(), bean,beanName,method,false); springValueRegistry.register(beanFactory,definition.getKey(),springValue); logger.debug("Monitoring{}",springValue); }catch(Throwableex){ logger.error("Failedtoenableautoupdatefeaturefor{}.{}",bean.getClass(), definition.getPropertyName()); } } //clear beanName2SpringValueDefinitions.removeAll(beanName); } @Override publicvoidsetBeanFactory(BeanFactorybeanFactory)throwsBeansException{ this.beanFactory=beanFactory; } }
以上就是JavaApollo是如何实现配置更新的的详细内容,更多关于JavaApollo配置更新的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。