欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

Apollo客戶端設(shè)計(jì)原理的源碼解析是怎樣的

這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)?lái)有關(guān) Apollo客戶端設(shè)計(jì)原理的源碼解析是怎樣的,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

成都創(chuàng)新互聯(lián)專注于中大型企業(yè)的成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)和網(wǎng)站改版、網(wǎng)站營(yíng)銷服務(wù),追求商業(yè)策劃與數(shù)據(jù)分析、創(chuàng)意藝術(shù)與技術(shù)開(kāi)發(fā)的融合,累計(jì)客戶上千家,服務(wù)滿意度達(dá)97%。幫助廣大客戶順利對(duì)接上互聯(lián)網(wǎng)浪潮,準(zhǔn)確優(yōu)選出符合自己需要的互聯(lián)網(wǎng)運(yùn)用,我們將一直專注成都品牌網(wǎng)站建設(shè)和互聯(lián)網(wǎng)程序開(kāi)發(fā),在前進(jìn)的路上,與客戶一起成長(zhǎng)!

1. 設(shè)計(jì)原理

圖 1 簡(jiǎn)要描述了 Apollo 客戶端的實(shí)現(xiàn)原理。

Apollo客戶端設(shè)計(jì)原理的源碼解析是怎樣的

  • 客戶端和服務(wù)端保持了一個(gè)長(zhǎng)連接,編譯配置的實(shí)時(shí)更新推送。

  • 定時(shí)拉取配置是客戶端本地的一個(gè)定時(shí)任務(wù),默認(rèn)為每 5 分鐘拉取一次,也可以通過(guò)在運(yùn)行時(shí)指定 System Property:apollo.refreshInterval 來(lái)覆蓋,單位是分鐘,推送+定時(shí)拉取=雙保險(xiǎn)。

  • 客戶端從 Apollo 配置中心服務(wù)端獲取到應(yīng)用的最新配置后,會(huì)保存在內(nèi)存中。

  • 客戶端會(huì)把從服務(wù)端獲取到的配置在本地文件系統(tǒng)緩存一份,當(dāng)服務(wù)或者網(wǎng)絡(luò)不可用時(shí),可以使用本地的配置,也就是我們的本地開(kāi)發(fā)模式 env=Local。

2. 和 Spring 集成的原理

Apollo 除了支持 API 方式獲取配置,也支持和 Spring/Spring Boot 集成,集成后可以直接通過(guò) @Value 獲取配置,我們來(lái)分析下集成的原理。

Spring 從 3.1 版本開(kāi)始增加了 ConfigurableEnvironment 和 PropertySource:

  • ConfigurableEnvironment 實(shí)現(xiàn)了 Environment 接口,并且包含了多個(gè) Property-Source。

  • PropertySource 可以理解為很多個(gè) Key-Value 的屬性配置,在運(yùn)行時(shí)的結(jié)構(gòu)形如圖 2 所示。

Apollo客戶端設(shè)計(jì)原理的源碼解析是怎樣的

需要注意的是,PropertySource 之間是有優(yōu)先級(jí)順序的,如果有一個(gè) Key 在多個(gè) property source 中都存在,那么位于前面的 property source 優(yōu)先。

集成的原理就是在應(yīng)用啟動(dòng)階段,Apollo 從遠(yuǎn)端獲取配置,然后組裝成 PropertySource 并插入到第一個(gè)即可,如圖 3 所示。

Apollo客戶端設(shè)計(jì)原理的源碼解析是怎樣的

3. 啟動(dòng)時(shí)初始化配置到 Spring

客戶端集成 Spring 的代碼分析,我們也采取簡(jiǎn)化的方式進(jìn)行講解。

首先我們來(lái)分析,在項(xiàng)目啟動(dòng)的時(shí)候從 Apollo 拉取配置,是怎么集成到 Spring 中的。創(chuàng)建一個(gè) PropertySourcesProcessor 類,用于初始化配置到 Spring PropertySource 中。具體代碼如下所示。

@Componentpublic class PropertySourcesProcessor implements BeanFactoryPostProcessor, EnvironmentAware {
    String APOLLO_PROPERTY_SOURCE_NAME = "ApolloPropertySources";private ConfigurableEnvironment environment;@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// 啟動(dòng)時(shí)初始化配置到Spring PropertySourceConfig config = new Config();
        ConfigPropertySource configPropertySource = new ConfigPropertySource("ap-plication", config);

        CompositePropertySource composite = new CompositePropertySource(APOLLO_PROPERTY_SOURCE_NAME);
        composite.addPropertySource(configPropertySource);

        environment.getPropertySources().addFirst(composite);
    }@Overridepublic void setEnvironment(Environment environment) {this.environment = (ConfigurableEnvironment) environment;
    }
}

實(shí)現(xiàn) EnvironmentAware 接口是為了獲取 Environment 對(duì)象。實(shí)現(xiàn) BeanFactory-Post-Processor 接口,我們可以在容器實(shí)例化 bean 之前讀取 bean 的信息并修改它。

Config 在 Apollo 中是一個(gè)接口,定義了很多讀取配置的方法,比如 getProperty:getIntProperty 等。通過(guò)子類去實(shí)現(xiàn)這些方法,在這里我們就簡(jiǎn)化下,直接定義成一個(gè)類,提供兩個(gè)必要的方法,具體代碼如下所示。

public class Config {public String getProperty(String key, String defaultValue) {if (key.equals("bianchengName")) {return "C語(yǔ)言中文網(wǎng)";
        }return null;
    }public Set<String> getPropertyNames() {
        Set<String> names = new HashSet<>();
        names.add("bianchengName");return names;
    }
}

Config 就是配置類,配置拉取之后會(huì)存儲(chǔ)在類中,所有配置的讀取都必須經(jīng)過(guò)它,我們?cè)谶@里就平格定義需要讀取的 key 為 bianchengName。

然后需要將 Config 封裝成 PropertySource 才能插入到 Spring Environment 中。

定義一個(gè) ConfigPropertySource 用于將 Config 封裝成 PropertySource,ConfigProperty-Source 繼承了 EnumerablePropertySource,EnumerablePropertySource 繼承了 PropertySource。具體代碼如下所示。

public class ConfigPropertySource extends EnumerablePropertySource<Config> {private static final String[] EMPTY_ARRAY = new String[0];

    ConfigPropertySource(String name, Config source) {super(name, source);
    }@Overridepublic String[] getPropertyNames() {
        Set<String> propertyNames = this.source.getPropertyNames();if (propertyNames.isEmpty()) {return EMPTY_ARRAY;
        }return propertyNames.toArray(new String[propertyNames.size()]);
    }@Overridepublic Object getProperty(String name) {return this.source.getProperty(name, null);
    }
}

需要做的操作還是重寫(xiě) getPropertyNames 和 getProperty 這兩個(gè)方法。當(dāng)調(diào)用這兩個(gè)方法時(shí),返回的就是 Config 中的內(nèi)容。

最后將 ConfigPropertySource 添加到 CompositePropertySource 中,并且加入到 Confi-gu-rable-Environment 即可。

定義一個(gè)接口用來(lái)測(cè)試有沒(méi)有效果,具體代碼如下所示。

@RestControllerpublic class ConfigController {@Value("${bianchengName:zhangsan}")private String name;@GetMapping("/get")private String bianchengUrl;@GetMapping("/get")public String get() {return name + bianchengUrl;
    }
}

在配置文件中增加對(duì)應(yīng)的配置:

bianchengName=xxx
bianchengUrl=http://minglisoft.cn/cloud

在沒(méi)有增加上面講的代碼之前,訪問(wèn) /get 接口返回的是 xxxhttp://c.biancheng.net。加上上面講解的代碼之后,返回的內(nèi)容就變成了猿天地 http://c.biancheng.net。

這是因?yàn)槲覀冊(cè)?Config 中對(duì)應(yīng) bianchengName 這個(gè) key 的返回值是猿天地,也間接證明了在啟動(dòng)的時(shí)候可以通過(guò)這種方式來(lái)覆蓋本地的值。這就是 Apollo 與 Spring 集成的原理。

4. 運(yùn)行中修改配置如何刷新

在這一節(jié)中,我們來(lái)講解下在項(xiàng)目運(yùn)行過(guò)程中,配置發(fā)生修改之后推送給了客戶端,那么這個(gè)值如何去更新 Spring 當(dāng)中的值呢?

原理就是把這些配置都存儲(chǔ)起來(lái),當(dāng)配置發(fā)生變化的時(shí)候進(jìn)行修改就可以。Apollo 中定義了一個(gè) SpringValueProcessor 類,用來(lái)處理 Spring 中值的修改。下面只貼出一部分代碼,如下所示。

@Componentpublic class SpringValueProcessor implements BeanPostProcessor, BeanFactoryAware {private PlaceholderHelper placeholderHelper = new PlaceholderHelper();private BeanFactory beanFactory;public SpringValueRegistry springValueRegistry = new SpringValueRegistry();@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Class clazz = bean.getClass();for (Field field : findAllField(clazz)) {
            processField(bean, beanName, field);
        }return bean;
    }private void processField(Object bean, String beanName, Field field) {// register @Value on fieldValue 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);
        }
    }
}

通過(guò)實(shí)現(xiàn) BeanPostProcessor 來(lái)處理每個(gè) bean 中的值,然后將這個(gè)配置信息封裝成一個(gè) SpringValue 存儲(chǔ)到 springValueRegistry 中。

SpringValue 代碼如下所示。

public class SpringValue {private MethodParameter methodParameter;private Field field;private Object bean;private String beanName;private String key;private String placeholder;private Class<?> targetType;private Type genericType;private boolean isJson;
}

SpringValueRegistry 就是利用 Map 來(lái)存儲(chǔ),代碼如下所示。

public class SpringValueRegistry {private final Map<BeanFactory, Multimap<String, SpringValue>> registry = Maps.newConcurrentMap();private final Object LOCK = new Object();public void register(BeanFactory beanFactory, String key, SpringValue springValue) {if (!registry.containsKey(beanFactory)) {
            synchronized (LOCK) {if (!registry.containsKey(beanFactory)) {
                    registry.put(beanFactory, LinkedListMultimap.<String, SpringValue>create());
                }
            }
        }
        registry.get(beanFactory).put(key, springValue);
    }public Collection<SpringValue> get(BeanFactory beanFactory, String key) {
        Multimap<String, SpringValue> beanFactorySpringValues = registry.get(beanFactory);if (beanFactorySpringValues == null) {return null;
        }return beanFactorySpringValues.get(key);
    }
}

寫(xiě)個(gè)接口用于模擬配置修改,具體代碼如下所示。

@RestControllerpublic class ConfigController {@Autowiredprivate SpringValueProcessor springValueProcessor;@Autowiredprivate ConfigurableBeanFactory beanFactory;@GetMapping("/update")public String update(String value) {
        Collection<SpringValue> targetValues = springValueProcessor.springValueRegistry.get(beanFactory,"bianchengName");for (SpringValue val : targetValues) {try {val.update(value);
            } catch (IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }return name;
    }
}

當(dāng)我們調(diào)用 /update接口后,在前面的 /get 接口可以看到猿天地的值改成了你傳入的那個(gè)值,這就是動(dòng)態(tài)修改。

通過(guò)閱讀 Apollo 的源碼,可以學(xué)到很多的東西。

  • Apollo 用的是 MySQL。Apollo 是多個(gè)庫(kù),通過(guò)庫(kù)來(lái)區(qū)分不同環(huán)境下的配置。

  • Apollo 基于 Http 長(zhǎng)連接實(shí)現(xiàn)推送,還有容災(zāi)的定時(shí)拉取邏輯。

  • Apollo 也有自己的原生獲取值的對(duì)象,同時(shí)還集成到了 Spring 中,可以兼容老項(xiàng)目的使用方式。

  • Apollo 中可以直接使用注解來(lái)進(jìn)行監(jiān)聽(tīng),非常方便。

上述就是小編為大家分享的 Apollo客戶端設(shè)計(jì)原理的源碼解析是怎樣的了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

名稱欄目:Apollo客戶端設(shè)計(jì)原理的源碼解析是怎樣的
標(biāo)題鏈接:http://aaarwkj.com/article40/jpopho.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)頁(yè)設(shè)計(jì)公司微信公眾號(hào)、網(wǎng)站收錄、品牌網(wǎng)站建設(shè)網(wǎng)站改版、搜索引擎優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都做網(wǎng)站
美腿丝袜清纯唯美亚洲另类| 日韩在线视频一区二区三| 欧美日韩一区二区三区激情| 中字幕人妻一区二区三区| 女同三人按摩高潮喷出| 国产亚洲欧美精品在线观看| 传媒视频在线观看网站| 中国一级黄片免费欧美| 日韩欧美另类精品在线| 国产免费成人在线视频| 国产精品十八禁在线看| 日本熟女视频中文字幕| 中文字幕人妻丝袜一区一三区| 精品成人在线一区二区| 国产精品日本欧美一区二区| 亚洲性视频日韩性视频| 在线观看高清国产黄色片| 色噜噜噜欧美人妻色综合| 日韩人妻精品在线一区二区| 欧美精品一区二区网址| 久热伊人精品国产中文| 精品黄色大片不卡国产| 亚洲一区二区三区三洲| 欧美亚洲精品在线观看| 国产午夜18久久久| 精品一区二区三区女同| 日本又色又爽又黄的观看 | 91九色国产原创在线观看| 国产又粗又爽视频免费| 日韩精品在线观看你懂的| 人妖激情一区二区三区| 18禁黄网站免费观看在线| 国产亚洲综合久久系列| 观看女性真实高潮的合集| 人妻一区日韩二区国产| 变态另类专区一区二区三区| 亚洲av激情码国产一区| 麻豆影片在线免费观看| 日本熟女俱乐部一区二区| 日韩精品伦理中文字幕| 偷拍大神女厕偷拍作品|