日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > javascript >内容正文

javascript

Spring Cloud Config 规范

發(fā)布時(shí)間:2024/8/23 javascript 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Cloud Config 规范 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Spring Cloud Config 規(guī)范

首先Spring Cloud 是基于 Spring 來擴(kuò)展的,Spring 本身就提供當(dāng)創(chuàng)建一個(gè)Bean時(shí)可從Environment 中將一些屬性值通過@Value的形式注入到業(yè)務(wù)代碼中的能力。那Spring Cloud Config 要解決的問題就是:

  • 如何將配置加載到 Environment 。
  • 配置變更時(shí),如何控制 Bean 是否需要 create,重新觸發(fā)一次 Bean 的初始化,才能將 @Value 注解指定的字段從 Environment 中重新注入。
  • 配置變更時(shí),如何控制新的配置會(huì)更新到 Environment 中,才能保證配置變更時(shí)可注入最新的值。
  • 要解決以上三個(gè)問題:Spring Cloud Config 規(guī)范中剛好定義了核心的三個(gè)接口:

  • PropertySourceLocator:抽象出這個(gè)接口,就是讓用戶可定制化的將一些配置加載到 Environment。這部分的配置獲取遵循了 Spring Cloud Config 的理念,即希望能從外部?jī)?chǔ)存介質(zhì)中來 loacte。
  • RefreshScope: Spring Cloud 定義這個(gè)注解,是擴(kuò)展了 Spring 原有的 Scope 類型。用來標(biāo)識(shí)當(dāng)前這個(gè) Bean 是一個(gè)refresh 類型的 Scope。其主要作用就是可以控制 Bean 的整個(gè)生命周期。
  • ContextRefresher:抽象出這個(gè) Class,是讓用戶自己按需來刷新上下文(比如當(dāng)有配置刷新時(shí),希望可以刷新上下文,將最新的配置更新到 Environment,重新創(chuàng)建 Bean 時(shí),就可以從 Environment 中注入最新的配置)。
  • Spring Cloud Config 原理

    Spring Cloud Config 的啟動(dòng)過程

    1、如何將配置加載到Environment:PropertySourceLocator

    在整個(gè) Spring Boot 啟動(dòng)的生命周期過程中,有一個(gè)階段是 prepare environment。在這個(gè)階段,會(huì)publish 一個(gè) ApplicationEnvironmentPreparedEvent,通知所有對(duì)這個(gè)事件感興趣的 Listener,提供對(duì) Environment 做更多的定制化的操作。Spring Cloud 定義了一個(gè)BootstrapApplicationListener,在 BootstrapApplicationListener 的處理過程中有一步非常關(guān)鍵的操作如下所示:

    private ConfigurableApplicationContext bootstrapServiceContext(ConfigurableEnvironment environment, final SpringApplication application,String configName) {//省略ClassLoader classLoader = Thread.currentThread().getContextClassLoader();// Use names and ensure unique to protect against duplicatesList<String> names = new ArrayList<>(SpringFactoriesLoader.loadFactoryNames(BootstrapConfiguration.class, classLoader));//省略}

    這是 Spring 的工廠加載機(jī)制,可通過在 META-INF/spring.factories 文件中配置一些程序中預(yù)定義的一些擴(kuò)展點(diǎn)。比如 Spring Cloud 這里的實(shí)現(xiàn),可以看到 BootstrapConfiguration 不是一個(gè)具體的接口,而是一個(gè)注解。通過這種方式配置的擴(kuò)展點(diǎn)好處是不局限于某一種接口的實(shí)現(xiàn),而是同一類別的實(shí)現(xiàn)??梢圆榭?spring-cloud-context 包中的 spring.factories 文件關(guān)于BootstrapConfiguration的配置,有一個(gè)比較核心入口的配置就是:

    org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration

    可以發(fā)現(xiàn) PropertySourceBootstrapConfiguration 實(shí)現(xiàn)了 ApplicationContextInitializer 接口,其目的就是在應(yīng)用程序上下文初始化的時(shí)候做一些額外的操作。在 Bootstrap 階段,會(huì)通過 Spring Ioc 的整個(gè)生命周期來初始化所有通過key為_org.springframework.cloud.bootstrap.BootstrapConfiguration_ 在 spring.factories 中配置的 Bean。Spring Cloud Alibaba Nacos Config 的實(shí)現(xiàn)就是通過該key來自定義一些在Bootstrap 階段需要初始化的一些Bean。在該模塊的 spring.factories 配置文件中可以看到如下配置:

    org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.alibaba.nacos.NacosConfigBootstrapConfiguration

    在 Bootstrap 階段初始化的過程中,會(huì)獲取所有 ApplicationContextInitializer 類型的 Bean,并設(shè)置回SpringApplication主流程當(dāng)中。如下 BootstrapApplicationListener 類中的部分代碼所示:

    ?

    private void apply(ConfigurableApplicationContext context, SpringApplication application, ConfigurableEnvironment environment) {@SuppressWarnings("rawtypes")//這里的 context 是一個(gè) bootstrap 級(jí)別的 ApplicationContext,這里已經(jīng)含有了在 bootstrap階段所有需要初始化的 Bean。//因此可以獲取 ApplicationContextInitializer.class 類型的所有實(shí)例List<ApplicationContextInitializer> initializers = getOrderedBeansOfType(context,ApplicationContextInitializer.class);//設(shè)置回 SpringApplication 主流程當(dāng)中application.addInitializers(initializers .toArray(new ApplicationContextInitializer[initializers.size()]));//省略... }

    ?

    這樣一來,就可以通過在 SpringApplication 的主流程中來回調(diào)這些ApplicationContextInitializer 的實(shí)例,做一些初始化的操作。如下 SpringApplication 類中的部分代碼所示:

    ?

    private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments, Banner printedBanner) {context.setEnvironment(environment);postProcessApplicationContext(context);//回調(diào)在BootstrapApplicationListener中設(shè)置的ApplicationContextInitializer實(shí)例applyInitializers(context);listeners.contextPrepared(context);//省略... }protected void applyInitializers(ConfigurableApplicationContext context) {for (ApplicationContextInitializer initializer : getInitializers()) {Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class);Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");initializer.initialize(context);} }

    ?

    在 applyInitializers 方法中,會(huì)觸發(fā) PropertySourceBootstrapConfiguration 中的 initialize 方法。如下所示:

    ?

    @Override public void initialize(ConfigurableApplicationContext applicationContext) {CompositePropertySource composite = new CompositePropertySource(BOOTSTRAP_PROPERTY_SOURCE_NAME);AnnotationAwareOrderComparator.sort(this.propertySourceLocators);boolean empty = true;ConfigurableEnvironment environment = applicationContext.getEnvironment();for (PropertySourceLocator locator : this.propertySourceLocators) {PropertySource<?> source = null;//回調(diào)所有實(shí)現(xiàn)PropertySourceLocator接口實(shí)例的locate方法,source = locator.locate(environment);if (source == null) {continue;}composite.addPropertySource(source);empty = false;}if (!empty) {//從當(dāng)前Enviroment中獲取 propertySourcesMutablePropertySources propertySources = environment.getPropertySources();//省略...//將composite中的PropertySource添加到當(dāng)前應(yīng)用上下文的propertySources中insertPropertySources(propertySources, composite);//省略...}

    ?

    在這個(gè)方法中會(huì)回調(diào)所有實(shí)現(xiàn) PropertySourceLocator 接口實(shí)例的locate方法,
    locate 方法返回一個(gè) PropertySource 的實(shí)例,統(tǒng)一add到CompositePropertySource實(shí)例中。如果 composite 中有新加的PropertySource,最后將composite中的PropertySource添加到當(dāng)前應(yīng)用上下文的propertySources中。Spring Cloud Alibaba Nacos Config 在 Bootstrap 階段通過Java配置的方式初始化了一個(gè) NacosPropertySourceLocator 類型的Bean。從而在 locate 方法中將存放在Nacos中的配置信息讀取出來,將讀取結(jié)果存放到 PropertySource 的實(shí)例中返回。具體如何從Nacos中讀取配置信息可參考 NacosPropertySourceLocator 類的實(shí)現(xiàn)。

    Spring Cloud Config 正是提供了PropertySourceLocator接口,來提供應(yīng)用外部化配置可動(dòng)態(tài)加載的能力。Spring Ioc 容器在初始化 Bean 的時(shí)候,如果發(fā)現(xiàn) Bean 的字段上含有 @Value 的注解,就會(huì)從 Enviroment 中的PropertySources 來獲取其值,完成屬性的注入。

    Spring Cloud Config 外部化配置可動(dòng)態(tài)刷新

    感知到外部化配置的變更這部分代碼的操作是需要用戶來完成的。Spring Cloud Config 只提供了具備外部化配置可動(dòng)態(tài)刷新的能力,并不具備自動(dòng)感知外部化配置發(fā)生變更的能力。比如如果你的配置是基于Mysql來實(shí)現(xiàn)的,那么在代碼里面肯定要有能力感知到配置發(fā)生變化了,然后再顯示的調(diào)用 ContextRefresher 的 refresh方法,從而完成外部化配置的動(dòng)態(tài)刷新(只會(huì)刷新使用RefreshScope注解的Bean)。

    例如在 Spring Cloud Alibaba Nacos Config 的實(shí)現(xiàn)過程中,Nacos 提供了對(duì)dataid 變更的Listener 回調(diào)。在對(duì)每個(gè)dataid 注冊(cè)好了相應(yīng)的Listener之后,如果Nacos內(nèi)部通過長(zhǎng)輪詢的方式感知到數(shù)據(jù)的變更,就會(huì)回調(diào)相應(yīng)的Listener,在 Listener 的實(shí)現(xiàn)過程中,就是通過調(diào)用 ContextRefresher 的 refresh方法完成配置的動(dòng)態(tài)刷新。具體可參考 NacosContextRefresher 類的實(shí)現(xiàn)。

    Sring Cloud Config的動(dòng)態(tài)配置刷新原理圖如下所示:

    ContextRefresher的refresh的方法主要做了兩件事:

  • 觸發(fā)PropertySourceLocator的locator方法,需要加載最新的值,并替換 Environment 中舊值
  • Bean中的引用配置值需要重新注入一遍。重新注入的流程是在Bean初始化時(shí)做的操作,那也就是需要將refresh scope中的Bean 緩存失效,當(dāng)再次從refresh scope中獲取這個(gè)Bean時(shí),發(fā)現(xiàn)取不到,就會(huì)重新觸發(fā)一次Bean的初始化過程。
  • 這兩個(gè)操作所對(duì)應(yīng)的代碼如下所示:

    ?

    public synchronized Set refresh() { Map<String, Object> before = extract(this.context.getEnvironment().getPropertySources());//1、加載最新的值,并替換Envrioment中舊值addConfigFilesToEnvironment();Set<String> keys = changes(before,extract(this.context.getEnvironment().getPropertySources())).keySet();this.context.publishEvent(new EnvironmentChangeEvent(context, keys));//2、將refresh scope中的Bean 緩存失效: 清空this.scope.refreshAll();return keys; }

    ?

    addConfigFilesToEnvironment 方法中發(fā)生替換的代碼如下所示:

    ?

    ConfigurableApplicationContext addConfigFilesToEnvironment() { ConfigurableApplicationContext capture = null;try {//省略...//1、這里會(huì)重新觸發(fā)PropertySourceLoactor的locate的方法,獲取最新的外部化配置capture = (SpringApplicationBuilder)builder.run();MutablePropertySources target = this.context.getEnvironment().getPropertySources();String targetName = null;for (PropertySource<?> source : environment.getPropertySources()) {String name = source.getName();//省略..//只有不是標(biāo)準(zhǔn)的 Source 才可替換if (!this.standardSources.contains(name)) {if (target.contains(name)) {//開始用新的PropertySource替換舊值target.replace(name, source);}//}}}//return capture; }

    ?

    this.scope.refreshAll() 清空緩存的操作代碼如下所示:

    @Overridepublic void destroy() {List<Throwable> errors = new ArrayList<Throwable>();//清空Refresh Scope 中的緩存Collection<BeanLifecycleWrapper> wrappers = this.cache.clear();//省略...}

    為了驗(yàn)證每次配置刷新時(shí),Bean 是新創(chuàng)建的,特意寫了一個(gè)Demo 驗(yàn)證了下,如下所示:

    Acm Properties: beijing-region //刷新前 Object Instance is :com.alibaba.demo.normal.ConfigProperties@1be9634 2018-11-01 19:16:32.535 INFO 27254 --- [gPullingdefault] startup date [Thu Nov 01 19:16:32 CST 2018]; root of context hierarchy Acm Properties: qingdao-region //刷新后 Object Instance is :com.alibaba.demo.normal.ConfigProperties@2c6965e0

    Spring Cloud Config 擴(kuò)展Scope的核心類:RefreshScope

    可以看到上面的代碼中有 this.scope.refreshAll(),其中的scope就是RefreshScope。是用來存放scope類型為refresh類型的Bean(即使用RefreshScope注解標(biāo)識(shí)的Bean),也就是說當(dāng)一個(gè)Bean既不是singleton也不是prototype時(shí),就會(huì)從自定義的Scope中去獲取(Spring 允許自定義Scope),然后調(diào)用Scope的get方法來獲取一個(gè)實(shí)例,Spring Cloud 正是擴(kuò)展了Scope,從而控制了整個(gè) Bean 的生命周期。當(dāng)配置需要?jiǎng)討B(tài)刷新的時(shí)候, 調(diào)用this.scope.refreshAll()這個(gè)方法,就會(huì)將整個(gè)RefreshScope的緩存清空,完成配置可動(dòng)態(tài)刷新的可能。

    更多關(guān)于Scope的分析請(qǐng)參考?這里

    后續(xù)

    關(guān)于ContextRefresh 和 RefreshScope的初始化配置是在RefreshAutoConfiguration類中完成的。而RefreshAutoConfiguration類初始化的入口是在spring-cloud-context中的META-INF/spring.factories中配置的。從而完成整個(gè)和動(dòng)態(tài)刷新相關(guān)的Bean的初始化操作。

    ?

    原文鏈接
    本文為云棲社區(qū)原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。

    總結(jié)

    以上是生活随笔為你收集整理的Spring Cloud Config 规范的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。