日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

服務(wù)端

1、服務(wù)端實(shí)時(shí)推送設(shè)計(jì)

新配置發(fā)布的大致流程

  • 用戶在 Portal 中進(jìn)行配置的編輯和發(fā)布。
  • Portal 會(huì)調(diào)用 Admin Service 提供的接口進(jìn)行發(fā)布操作。
  • Admin Service 收到請求后,發(fā)送 ReleaseMessage 給各個(gè) Config Service,通知 Config Service 配置發(fā)生變化。
  • Config Service 收到 ReleaseMessage 后,通知對應(yīng)的客戶端,基于 Http 長連接實(shí)現(xiàn)。

 

2. 發(fā)送 ReleaseMessage 的實(shí)現(xiàn)方式

ReleaseMessage 消息是通過 MySQL 實(shí)現(xiàn)了一個(gè)簡單的消息隊(duì)列。之所以沒有采用消息中間件,是為了讓 Apollo 在部署的時(shí)候盡量簡單,盡可能減少外部依賴

發(fā)送 ReleaseMessage 的實(shí)現(xiàn)方式

  • Admin Service 在配置發(fā)布后會(huì)往 ReleaseMessage 表插入一條消息記錄。
  • Config Service 會(huì)啟動(dòng)一個(gè)線程定時(shí)掃描 ReleaseMessage 表,來查看是否有新的消息記錄。
  • Config Service 發(fā)現(xiàn)有新的消息記錄,就會(huì)通知到所有的消息監(jiān)聽器。
  • 消息監(jiān)聽器得到配置發(fā)布的信息后,就會(huì)通知對應(yīng)的客戶端。

3. Config Service 通知客戶端的實(shí)現(xiàn)方式

通知采用基于 Http 長連接實(shí)現(xiàn),主要分為下面幾個(gè)步驟:

  • 客戶端會(huì)發(fā)起一個(gè) Http 請求到 Config Service 的 notifications/v2 接口。
  • notifications/v2 接口通過 Spring DeferredResult 把請求掛起,不會(huì)立即返回。
  • 如果在 60s 內(nèi)沒有該客戶端關(guān)心的配置發(fā)布,那么會(huì)返回 Http 狀態(tài)碼 304 給客戶端。
  • 如果發(fā)現(xiàn)配置有修改,則會(huì)調(diào)用 DeferredResult 的 setResult 方法,傳入有配置變化的 namespace 信息,同時(shí)該請求會(huì)立即返回。
  • 客戶端從返回的結(jié)果中獲取到配置變化的 namespace 后,會(huì)立即請求 Config Service 獲取該 namespace 的最新配置。

客戶端

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

Apollo 客戶端的實(shí)現(xiàn)原理

  • 客戶端和服務(wù)端保持了一個(gè)長連接,編譯配置的實(shí)時(shí)更新推送。
  • 定時(shí)拉取配置是客戶端本地的一個(gè)定時(shí)任務(wù),默認(rèn)為每 5 分鐘拉取一次,也可以通過在運(yùn)行時(shí)指定 System Property:apollo.refreshInterval 來覆蓋,單位是分鐘,推送+定時(shí)拉取=雙保險(xiǎn)。
  • 客戶端從 Apollo 配置中心服務(wù)端獲取到應(yīng)用的最新配置后,會(huì)保存在內(nèi)存中。
  • 客戶端會(huì)把從服務(wù)端獲取到的配置在本地文件系統(tǒng)緩存一份,當(dāng)服務(wù)或者網(wǎng)絡(luò)不可用時(shí),可以使用本地的配置,也就是我們的本地開發(fā)模式 env=Local。

2、與 Spring 集成后通過 @Value 獲取配置原理

Spring 從 3.1 版本開始增加了 ConfigurableEnvironment 和 PropertySource:

  • ConfigurableEnvironment 實(shí)現(xiàn)了 Environment 接口,并且包含了多個(gè) PropertySource
  • PropertySource 可以理解為很多個(gè) Key-Value 的屬性配置,在運(yùn)行時(shí)的結(jié)構(gòu)形如下圖所示。

Spring 配置結(jié)構(gòu)

需要注意的是,PropertySource 之間是有優(yōu)先級順序的,如果有一個(gè) Key 在多個(gè) property source 中都存在,那么位于前面的 property source 優(yōu)先。
集成的原理就是在應(yīng)用啟動(dòng)階段,Apollo 從遠(yuǎn)端獲取配置,然后組裝成 PropertySource 并插入到第一個(gè)即可,如下圖所示。

 

3、動(dòng)態(tài)刷新配置的實(shí)現(xiàn)原理

Apollo Client 中定義了 SpringValueProcessor 類,其實(shí)現(xiàn)了 BeanPostProcessor 用于處理值修改。

public class SpringValueProcessor extends ApolloProcessor implements BeanFactoryPostProcessor, BeanFactoryAware {
  
  private PlaceholderHelper placeholderHelper = new PlaceholderHelper();
	private BeanFactory beanFactory;
  public SpringValueRegistry springValueRegistry = new SpringValueRegistry();

    @Override
    public 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 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);
        }
    }
  
}

通過實(shí)現(xiàn) BeanPostProcessor 來處理每個(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 來存儲(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);
    }
}

當(dāng)
AutoUpdateConfigChangeListener 監(jiān)聽到變化就會(huì)調(diào)用 onChange 更新值

public class AutoUpdateConfigChangeListener implements ConfigChangeListener{
  
    private final SpringValueRegistry springValueRegistry;
  
  	@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);
        }
      }
    }

}

最后

本文參考

http://c.biancheng.NET/view/5480.html

http://c.biancheng.net/view/5482.html

分享到:
標(biāo)簽:Apollo
用戶無頭像

網(wǎng)友整理

注冊時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定