电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術(shù)文章
文章詳情頁

Java Apollo是如何實現(xiàn)配置更新的

瀏覽:9日期:2022-08-15 17:54:26

這篇文檔主要關(guān)注下配置修改后對應(yīng)的 Java 對象是如何更新,并不關(guān)注整體的配置改動流程

所有代碼都來自 apollo-client 項目

更新流程

在 Apollo 控制臺進行配置修改并發(fā)布后,對應(yīng)的 client 端拉取到更新后,會調(diào)用到 com.ctrip.framework.apollo.spring.property.AutoUpdateConfigChangeListener#onChange 方法

在調(diào)用 onChange 會收到對應(yīng)的修改的配置信息 ConfigChangeEvent, 其中包含改動的 key 和 value, 則改動流程如下:

根據(jù)改動的配置的 key 從 springValueRegistry 找到對應(yīng)的關(guān)聯(lián)到這個 key 的 Spring Bean 信息,如果找不到則不處理 根據(jù)找到的 Spring Bean 信息,進行對應(yīng)關(guān)聯(lián)配置的更新

在第二步中會判斷關(guān)聯(lián)配置是用過屬性關(guān)聯(lián)還是方法進行關(guān)聯(lián)的,代碼如下

public void update(Object newVal) throws IllegalAccessException, InvocationTargetException { if (isField()) { injectField(newVal); } else { injectMethod(newVal); }}

在上面的問題中,還有兩個問題存疑

如何通過 key 找到對應(yīng)的 Spring Bean 信息 如何將 Apollo 的配置值轉(zhuǎn)換為 Spring 的識別的值

public class AutoUpdateConfigChangeListener implements ConfigChangeListener{ private static final Logger logger = LoggerFactory.getLogger(AutoUpdateConfigChangeListener.class); private final boolean typeConverterHasConvertIfNecessaryWithFieldParameter; private final Environment environment; private final ConfigurableBeanFactory beanFactory; private final TypeConverter typeConverter; private final PlaceholderHelper placeholderHelper; private final SpringValueRegistry springValueRegistry; private final Gson gson; public AutoUpdateConfigChangeListener(Environment environment, ConfigurableListableBeanFactory beanFactory){ 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 = new Gson(); } @Override public void onChange(ConfigChangeEvent changeEvent) { Set<String> keys = changeEvent.changedKeys(); if (CollectionUtils.isEmpty(keys)) { return; } for (String key : keys) { // 1. check whether the changed key is relevant Collection<SpringValue> targetValues = springValueRegistry.get(beanFactory, key); if (targetValues == null || targetValues.isEmpty()) { continue; } // 2. update the value for (SpringValue val : targetValues) { updateSpringValue(val); } } } private void updateSpringValue(SpringValue springValue) { try { Object value = resolvePropertyValue(springValue); springValue.update(value); logger.info('Auto update apollo changed value successfully, new value: {}, {}', value, springValue); } catch (Throwable ex) { logger.error('Auto update apollo changed value failed, {}', springValue.toString(), ex); } } /** * Logic transplanted from DefaultListableBeanFactory * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency(org.springframework.beans.factory.config.DependencyDescriptor, java.lang.String, java.util.Set, org.springframework.beans.TypeConverter) */ private Object resolvePropertyValue(SpringValue springValue) { // value will never be null, as @Value and @ApolloJsonValue will not allow that Object value = 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) is available from Spring 3.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()); } } return value; } private Object parseJsonValue(String json, Type targetType) { try { return gson.fromJson(json, targetType); } catch (Throwable ex) { logger.error('Parsing json ’{}’ to type {} failed!', json, targetType, ex); throw ex; } } private boolean testTypeConverterHasConvertIfNecessaryWithFieldParameter() { try { TypeConverter.class.getMethod('convertIfNecessary', Object.class, Class.class, Field.class); } catch (Throwable ex) { return false; } return true; }}如何將配置 key 和 Spring Bean 關(guān)聯(lián)起來

在 Spring 常見配置包括 2 種

public class ApiConfig { // 1. 直接在 Field 是進行注入 @Value('${feifei.appId}') protected String appId; protected String predUrl; // 2. 在方法上進行注入 @Value('${predUrl}') public void setPredUrl(String predUrl) { this.predUrl = predUrl; }}

在 Apollo 代碼中,通過實現(xiàn) BeanPostProcessor 接口來檢測所有的Spring Bean 的創(chuàng)建過程,在 Spring Bean 創(chuàng)建的過程中會調(diào)用對應(yīng)的 org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization 和 org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization 方法。

Apollo 通過在 Bean 生成過程中,檢測 Bean 類中屬性和方法是否存在 @Value 注解,如果存在,提出其中的 key, 其處理方法在 processField 和 processMethod 分別處理 Field 和 Method 中可能出現(xiàn)的 @Value 注解。如果存在注解則將對應(yīng)的信息存到 SpringValue 對應(yīng) springValueRegistry 全局對象中,方便在其它地方可以直接獲取。

在屬性除了通過 @Value 注入,也可以用過 xml 進行配置,在這種情況通過 processBeanPropertyValues 方法來處理

通過兩種處理方式就可以將 key 和對應(yīng)的 Spring Bean 信息關(guān)聯(lián)起來

public class SpringValueProcessor extends ApolloProcessor implements BeanFactoryPostProcessor, BeanFactoryAware { private static final Logger logger = LoggerFactory.getLogger(SpringValueProcessor.class); private final ConfigUtil configUtil; private final PlaceholderHelper placeholderHelper; private final SpringValueRegistry springValueRegistry; private BeanFactory beanFactory; private Multimap<String, SpringValueDefinition> beanName2SpringValueDefinitions; public SpringValueProcessor() { configUtil = ApolloInjector.getInstance(ConfigUtil.class); placeholderHelper = SpringInjector.getInstance(PlaceholderHelper.class); springValueRegistry = SpringInjector.getInstance(SpringValueRegistry.class); beanName2SpringValueDefinitions = LinkedListMultimap.create(); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled() && beanFactory instanceof BeanDefinitionRegistry) { beanName2SpringValueDefinitions = SpringValueDefinitionProcessor .getBeanName2SpringValueDefinitions((BeanDefinitionRegistry) beanFactory); } } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) { super.postProcessBeforeInitialization(bean, beanName); processBeanPropertyValues(bean, beanName); } return bean; } @Override protected void processField(Object bean, String beanName, Field field) { // register @Value on field Value value = field.getAnnotation(Value.class); if (value == null) { return; } Set<String> keys = placeholderHelper.extractPlaceholderKeys(value.value()); if (keys.isEmpty()) { return; } for (String key : keys) { SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, field, false); springValueRegistry.register(beanFactory, key, springValue); logger.debug('Monitoring {}', springValue); } } @Override protected void processMethod(Object bean, String beanName, Method method) { //register @Value on method Value value = method.getAnnotation(Value.class); if (value == null) { return; } //skip Configuration bean methods if (method.getAnnotation(Bean.class) != null) { return; } if (method.getParameterTypes().length != 1) { logger.error('Ignore @Value setter {}.{}, expecting 1 parameter, actual {} parameters', bean.getClass().getName(), method.getName(), method.getParameterTypes().length); return; } Set<String> keys = placeholderHelper.extractPlaceholderKeys(value.value()); if (keys.isEmpty()) { return; } for (String key : keys) { SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, method, false); springValueRegistry.register(beanFactory, key, springValue); logger.info('Monitoring {}', springValue); } } private void processBeanPropertyValues(Object bean, String beanName) { Collection<SpringValueDefinition> propertySpringValues = beanName2SpringValueDefinitions .get(beanName); if (propertySpringValues == null || propertySpringValues.isEmpty()) { return; } for (SpringValueDefinition definition : propertySpringValues) { try { PropertyDescriptor pd = BeanUtils .getPropertyDescriptor(bean.getClass(), definition.getPropertyName()); Method method = pd.getWriteMethod(); if (method == null) { continue; } SpringValue springValue = new SpringValue(definition.getKey(), definition.getPlaceholder(), bean, beanName, method, false); springValueRegistry.register(beanFactory, definition.getKey(), springValue); logger.debug('Monitoring {}', springValue); } catch (Throwable ex) { logger.error('Failed to enable auto update feature for {}.{}', bean.getClass(), definition.getPropertyName()); } } // clear beanName2SpringValueDefinitions.removeAll(beanName); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; }}

以上就是Java Apollo是如何實現(xiàn)配置更新的的詳細內(nèi)容,更多關(guān)于Java Apollo 配置更新的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 工业风机_环保空调_冷风机_工厂车间厂房通风降温设备旺成服务平台 | 骨龄仪_骨龄检测仪_儿童骨龄测试仪_品牌生产厂家【品源医疗】 | 天津电机维修|水泵维修-天津晟佳机电设备有限公司 | 液压油缸-液压站生产厂家-洛阳泰诺液压科技有限公司 | 氧化铁红厂家-淄博宗昂化工 | 拖鞋定制厂家-品牌拖鞋代加工厂-振扬实业中国高端拖鞋大型制造商 | 日本细胞免疫疗法_肿瘤免疫治疗_NK细胞疗法 - 免疫密码 | 武汉天安盾电子设备有限公司 - 安盾安检,武汉安检门,武汉安检机,武汉金属探测器,武汉测温安检门,武汉X光行李安检机,武汉防爆罐,武汉车底安全检查,武汉液体探测仪,武汉安检防爆设备 | 钢格板|热镀锌钢格板|钢格栅板|钢格栅|格栅板-安平县昊泽丝网制品有限公司 | 上海赞永| 全自动烧卖机厂家_饺子机_烧麦机价格_小笼汤包机_宁波江北阜欣食品机械有限公司 | 塑料检查井_双扣聚氯乙烯增强管_双壁波纹管-河南中盈塑料制品有限公司 | 电销卡_北京电销卡_包月电话卡-豪付网络 | 胃口福饺子加盟官网_新鲜现包饺子云吞加盟 - 【胃口福唯一官网】 | 山楂片_雪花_迷你山楂片_山楂条饼厂家-青州市丰源食品厂 | 厦门网站建设_厦门网站设计_小程序开发_网站制作公司【麦格科技】 | 浙江富广阀门有限公司| 贵州水玻璃_-贵阳花溪闽兴水玻璃厂| 广州工业氧气-工业氩气-工业氮气-二氧化碳-广州市番禺区得力气体经营部 | 高空重型升降平台_高空液压举升平台_高空作业平台_移动式升降机-河南华鹰机械设备有限公司 | 胶辊硫化罐_胶鞋硫化罐_硫化罐厂家-山东鑫泰鑫智能装备有限公司 意大利Frascold/富士豪压缩机_富士豪半封闭压缩机_富士豪活塞压缩机_富士豪螺杆压缩机 | 缝纫客| 培训中心-海南香蕉蛋糕加盟店技术翰香原中心官网总部 | 包塑丝_高铁绑丝_地暖绑丝_涂塑丝_塑料皮铁丝_河北创筹金属丝网制品有限公司 | 真空包装机-诸城市坤泰食品机械有限公司| 杭州荣奥家具有限公司-浙江办公家具,杭州办公家具厂 | 【黄页88网】-B2B电子商务平台,b2b平台免费发布信息网 | 铝板冲孔网,不锈钢冲孔网,圆孔冲孔网板,鳄鱼嘴-鱼眼防滑板,盾构走道板-江拓数控冲孔网厂-河北江拓丝网有限公司 | 政府园区专业委托招商平台_助力企业选址项目快速落地_东方龙商务集团 | Magnescale探规,Magnescale磁栅尺,Magnescale传感器,Magnescale测厚仪,Mitutoyo光栅尺,笔式位移传感器-苏州连达精密量仪有限公司 | 两头忙,井下装载机,伸缩臂装载机,30装载机/铲车,50装载机/铲车厂家_价格-莱州巨浪机械有限公司 | 杜甫仪器官网|实验室平行反应器|升降水浴锅|台式低温循环泵 | 玉米深加工设备-玉米深加工机械-新型玉米工机械生产厂家-河南粮院机械制造有限公司 | 袋式过滤器,自清洗过滤器,保安过滤器,篮式过滤器,气体过滤器,全自动过滤器,反冲洗过滤器,管道过滤器,无锡驰业环保科技有限公司 | 广东机电安装工程_中央空调工程_东莞装饰装修-广东粤标建设有限公司 | 胶原检测试剂盒,弹性蛋白检测试剂盒,类克ELISA试剂盒,阿达木单抗ELISA试剂盒-北京群晓科苑生物技术有限公司 | 中药二氧化硫测定仪,食品二氧化硫测定仪|俊腾百科 | 深圳律师咨询_深圳律师事务所_华荣【免费在线法律咨询】网 | 灌木树苗-绿化苗木-常绿乔木-价格/批发/基地 - 四川成都途美园林 | 铝合金重力铸造_铝合金翻砂铸造_铝铸件厂家-东莞市铝得旺五金制品有限公司 | 旅游规划_旅游策划_乡村旅游规划_景区规划设计_旅游规划设计公司-北京绿道联合旅游规划设计有限公司 |