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
CollectiontargetValues=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;
}
Setkeys=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;
}
Setkeys=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){
CollectionpropertySpringValues=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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。