最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot用配置影響B(tài)ean加載@ConditionalOnProperty

 更新時(shí)間:2023年04月06日 10:06:55   作者:樹葉小記  
這篇文章主要為大家介紹了SpringBoot用配置影響B(tài)ean加載@ConditionalOnProperty示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

故事背景

故事發(fā)生在幾個(gè)星期前,自動(dòng)化平臺(tái)代碼開放給整個(gè)測(cè)試團(tuán)隊(duì)以后,越來(lái)越多的同事開始探索平臺(tái)代碼。為了保障自動(dòng)化測(cè)試相關(guān)的數(shù)據(jù)和沉淀能不被污染,把數(shù)據(jù)庫(kù)進(jìn)行了隔離。終于有了2個(gè)數(shù)據(jù)庫(kù)實(shí)例,一個(gè)給dev環(huán)境用,一個(gè)給test環(huán)境用??墒请S著平臺(tái)的發(fā)展,越來(lái)越多的中間件被引用了。所以需要隔離的東西就越來(lái)越多了,比如MQ,Redis等。成本越來(lái)越高,如果像數(shù)據(jù)庫(kù)實(shí)例一樣全部分開搞一套,那在當(dāng)下全域降本增效的大潮下,也是困難重重。
?

通過(guò)線下觀察和走訪發(fā)現(xiàn),這些探索的同學(xué)并不是需要全平臺(tái)的能力,其中有很多模塊或者子系統(tǒng),同學(xué)并不關(guān)心。因此就產(chǎn)生了一個(gè)想法,隔離掉這些類或者不使用這些和中間件相關(guān)的類應(yīng)該就可以了 。而后因?yàn)槲覀兊钠脚_(tái)是基于springboot開發(fā)的,自然而然的想到了@Conditional注解。

調(diào)試&解決

以AWS SQS為例,先添加上了注解@ConditionalOnProperty根據(jù)配置信息中的coverage.aws.topic屬性進(jìn)行判斷,如果存在這個(gè)配置就進(jìn)行CoverageSQSConfig的Spring Bean的加載。

@Configuration
@ConditionalOnProperty(
        name = "coverage.aws.topic"
)
public class CoverageSQSConfig {
    @Value("${coverage.aws.region}")
    private String awsRegion;
    @Value("${coverage.aws.access.key}")
    private String accessKey;
    @Value("${coverage.aws.secret.key}")
    private String secretKey;
    @Bean(name = "coverageSQSListenerFactory")
    public DefaultJmsListenerContainerFactory sqsListenerContainerFactory(){
        return getDefaultJmsListenerContainerFactory(awsRegion, accessKey, secretKey);
    }
    private DefaultJmsListenerContainerFactory getDefaultJmsListenerContainerFactory(String awsRegion, String accessKey, String secretKey) {
        DefaultJmsListenerContainerFactory sqsFactory = new DefaultJmsListenerContainerFactory();
        sqsFactory.setConnectionFactory(new SQSConnectionFactory(
                new ProviderConfiguration(),
                AmazonSQSClientBuilder.standard()
                        .withRegion(Region.of(awsRegion).id())
                        .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey)))
                        .build()));
        sqsFactory.setConcurrency("3-10");
        sqsFactory.setReceiveTimeout(10*1000L);
        sqsFactory.setRecoveryInterval(1000L);
        return sqsFactory;
    }
}

為調(diào)試這個(gè)內(nèi)容的效果,這里列出了2次調(diào)試的效果對(duì)比:首先是把備注字段全部都注釋掉。

通過(guò)上圖很明顯,當(dāng)coverage.aws.topic屬性不存在的時(shí)候,不能找到被Spring統(tǒng)一管理的bean。

第二次是把備注的注釋都取消掉,重啟后能找到bean。

問(wèn)題解決了嗎?當(dāng)時(shí)就想再看下SpringBoot是怎么做的通過(guò)這個(gè)注解就這么方便的過(guò)濾了這個(gè)bean的加載,以及是否有什么其他的用法或者特性。

SpringBoot 是怎么做的

通過(guò)@ConditionalOnProperty注解,很快能定位到它是位于 autoconfigure模塊的特性。**
**

順藤摸瓜,很快就能找到注解是在哪里進(jìn)行使用的

package org.springframework.boot.autoconfigure.condition;
...
@Order(Ordered.HIGHEST_PRECEDENCE + 40)
class OnPropertyCondition extends SpringBootCondition {
  @Override
  public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
    // 通過(guò)獲類原始數(shù)據(jù)上的ConditionalOnProperty注解的參數(shù)值
    List<AnnotationAttributes> allAnnotationAttributes = annotationAttributesFromMultiValueMap(
        metadata.getAllAnnotationAttributes(ConditionalOnProperty.class.getName()));
    List<ConditionMessage> noMatch = new ArrayList<>();
    List<ConditionMessage> match = new ArrayList<>();
    for (AnnotationAttributes annotationAttributes : allAnnotationAttributes) {
     // 通過(guò)屬性值,逐一判斷配置信息中的信息是否滿足 , context.getEnvironment() 能獲取到所有的配置信息
      ConditionOutcome outcome = determineOutcome(annotationAttributes, context.getEnvironment());
      (outcome.isMatch() ? match : noMatch).add(outcome.getConditionMessage());
    }
    if (!noMatch.isEmpty()) {
      return ConditionOutcome.noMatch(ConditionMessage.of(noMatch));
    }
    return ConditionOutcome.match(ConditionMessage.of(match));
  }
  private List<AnnotationAttributes> annotationAttributesFromMultiValueMap(
      MultiValueMap<String, Object> multiValueMap) {
    ...
    return annotationAttributes;
  }
  private ConditionOutcome determineOutcome(AnnotationAttributes annotationAttributes, PropertyResolver resolver) {
    Spec spec = new Spec(annotationAttributes);
    List<String> missingProperties = new ArrayList<>();
    List<String> nonMatchingProperties = new ArrayList<>();
    // 通過(guò)屬性值,判斷配置信息中的信息是否滿足
    spec.collectProperties(resolver, missingProperties, nonMatchingProperties);
    if (!missingProperties.isEmpty()) {
      return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnProperty.class, spec)
          .didNotFind("property", "properties").items(Style.QUOTE, missingProperties));
    }
    if (!nonMatchingProperties.isEmpty()) {
      return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnProperty.class, spec)
          .found("different value in property", "different value in properties")
          .items(Style.QUOTE, nonMatchingProperties));
    }
    return ConditionOutcome
        .match(ConditionMessage.forCondition(ConditionalOnProperty.class, spec).because("matched"));
  }
  private static class Spec {
    private final String prefix;
    private final String havingValue;
    private final String[] names;
    private final boolean matchIfMissing;
    Spec(AnnotationAttributes annotationAttributes) {
      ...
    }
    private String[] getNames(Map<String, Object> annotationAttributes) {
      ...
    }
    private void collectProperties(PropertyResolver resolver, List<String> missing, List<String> nonMatching) {
      for (String name : this.names) {
        String key = this.prefix + name;
        if (resolver.containsProperty(key)) {
        // havingValue 默認(rèn)為 "" 
          if (!isMatch(resolver.getProperty(key), this.havingValue)) {
            nonMatching.add(name);
          }
        }
        else {
          if (!this.matchIfMissing) {
            missing.add(name);
          }
        }
      }
    }
    private boolean isMatch(String value, String requiredValue) {
      if (StringUtils.hasLength(requiredValue)) {
        return requiredValue.equalsIgnoreCase(value);
      }
      // havingValue 默認(rèn)為 "" ,因此只要對(duì)應(yīng)的屬性不為false,在注解中沒(méi)填havingValue的情況下,都是會(huì)match上conditon,即都會(huì)被加載
      return !"false".equalsIgnoreCase(value);
    }
    @Override
    public String toString() {
      ...
    }
  }
}

用這種方式進(jìn)行SpingBoot擴(kuò)展的也特別多,SpingBoot自己的autoconfigure模塊中有很多模塊的增強(qiáng)用的也是這個(gè)注解。

那他是在哪個(gè)環(huán)節(jié)進(jìn)行的這個(gè)condition的判斷呢?簡(jiǎn)單標(biāo)注如下:

其中判斷過(guò)濾的總?cè)肟冢?/p>

// org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider
  /**
   * Determine whether the given class does not match any exclude filter
   * and does match at least one include filter.
   * @param metadataReader the ASM ClassReader for the class
   * @return whether the class qualifies as a candidate component
   */
  protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
    for (TypeFilter tf : this.excludeFilters) {
      if (tf.match(metadataReader, getMetadataReaderFactory())) {
        return false;
      }
    }
    for (TypeFilter tf : this.includeFilters) {
      if (tf.match(metadataReader, getMetadataReaderFactory())) {
        // conditons 相關(guān)的入口,
        return isConditionMatch(metadataReader);
      }
    }
    return false;
  }

環(huán)顧整個(gè)流程,這里比較好的一點(diǎn)就是一旦條件過(guò)濾后,那就對(duì)類元文件里面的其他內(nèi)容也不進(jìn)行加載,像下面的@Value和@Bean的填充也不會(huì)進(jìn)行,能優(yōu)雅高效的解決掉當(dāng)前的問(wèn)題。

    @Value("${coverage.aws.region}")
    private String awsRegion;
    @Value("${coverage.aws.access.key}")
    private String accessKey;
    @Value("${coverage.aws.secret.key}")
    private String secretKey;
    @Bean(name = "coverageSQSListenerFactory")
    public DefaultJmsListenerContainerFactory sqsListenerContainerFactory(){
        return getDefaultJmsListenerContainerFactory(awsRegion, accessKey, secretKey);
    }

故事的最后

做完這個(gè)改動(dòng)以后,就提交了代碼,媽媽再也不用擔(dān)心因?yàn)槠渌瞬恍⌒氖褂媚承┲挥幸粋€(gè)實(shí)例的中間件導(dǎo)致數(shù)據(jù)污染了。用注解方式解決這個(gè)通過(guò)配置就能控制加載bean的這個(gè)能力確實(shí)很方便很Boot。比如中間件團(tuán)隊(duì)提供組件能力給團(tuán)隊(duì),用condtion的這個(gè)特性也是能方便落地的。當(dāng)然condition里面還有其他的一些特性,這里只是拋磚引玉,簡(jiǎn)單的梳理一下最近的一個(gè)使用場(chǎng)景。

以上就是SpringBoot用配置影響B(tài)ean加載@ConditionalOnProperty的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Bean加載@ConditionalOnProperty的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java中計(jì)算字符串長(zhǎng)度的方法及u4E00與u9FBB的認(rèn)識(shí)

    java中計(jì)算字符串長(zhǎng)度的方法及u4E00與u9FBB的認(rèn)識(shí)

    字符串采用unicode編碼的方式時(shí),計(jì)算字符串長(zhǎng)度的方法找出UNICODE編碼中的漢字的代表的范圍“\u4E00” 到“\u9FBB”之間感興趣的朋友可以參考本文,或許對(duì)你有所幫助
    2013-01-01
  • java內(nèi)存溢出示例(堆溢出、棧溢出)

    java內(nèi)存溢出示例(堆溢出、棧溢出)

    這篇文章主要介紹了java內(nèi)存溢出示例(堆溢出、棧溢出),需要的朋友可以參考下
    2014-04-04
  • Java匿名類和匿名函數(shù)的概念和寫法

    Java匿名類和匿名函數(shù)的概念和寫法

    匿名函數(shù)寫法和匿名類寫法的前提必須基于函數(shù)式接口匿名函數(shù)寫法和匿名類寫法其本質(zhì)是同一個(gè)東西,只是簡(jiǎn)化寫法不同使用Lambda表達(dá)式簡(jiǎn)寫匿名函數(shù)時(shí),可以同時(shí)省略實(shí)現(xiàn)類名、函數(shù)名,這篇文章主要介紹了Java匿名類和匿名函數(shù)的概念和寫法,需要的朋友可以參考下
    2023-06-06
  • Java?Agent?(代理)探針技術(shù)詳情

    Java?Agent?(代理)探針技術(shù)詳情

    這篇文章主要介紹了Java?Agent?探針技術(shù)詳情,Java?中的?Agent?技術(shù)可以讓我們無(wú)侵入性的去進(jìn)行代理,最常用于程序調(diào)試、熱部署、性能診斷分析等場(chǎng)景,下文更多相關(guān)資料,感興趣的小伙伴可以參考一下
    2022-04-04
  • java代理模式(靜態(tài)代理、動(dòng)態(tài)代理、cglib代理)

    java代理模式(靜態(tài)代理、動(dòng)態(tài)代理、cglib代理)

    代理(Proxy)是一種設(shè)計(jì)模式,提供了對(duì)目標(biāo)對(duì)象另外的訪問(wèn)方式;這篇文章主要介紹了Java 中的三種代理模式,需要的朋友可以參考下,希望能給你帶來(lái)幫助
    2021-07-07
  • java建立子類方法總結(jié)

    java建立子類方法總結(jié)

    在本篇文章里小編給大家分享了關(guān)于java建子類的步驟和方法,需要的朋友們跟著學(xué)習(xí)下。
    2019-05-05
  • Quartz實(shí)現(xiàn)JAVA定時(shí)任務(wù)的動(dòng)態(tài)配置的方法

    Quartz實(shí)現(xiàn)JAVA定時(shí)任務(wù)的動(dòng)態(tài)配置的方法

    這篇文章主要介紹了Quartz實(shí)現(xiàn)JAVA定時(shí)任務(wù)的動(dòng)態(tài)配置的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • java操作gaussDB數(shù)據(jù)庫(kù)的實(shí)現(xiàn)示例

    java操作gaussDB數(shù)據(jù)庫(kù)的實(shí)現(xiàn)示例

    本文主要介紹了java操作gaussDB數(shù)據(jù)庫(kù)的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Java向上轉(zhuǎn)型和向下轉(zhuǎn)型的區(qū)別說(shuō)明

    Java向上轉(zhuǎn)型和向下轉(zhuǎn)型的區(qū)別說(shuō)明

    這篇文章主要介紹了Java向上轉(zhuǎn)型和向下轉(zhuǎn)型的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • JavaWeb實(shí)現(xiàn)簡(jiǎn)單查詢商品功能

    JavaWeb實(shí)現(xiàn)簡(jiǎn)單查詢商品功能

    這篇文章主要為大家詳細(xì)介紹了JavaWeb實(shí)現(xiàn)簡(jiǎn)單查詢商品功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-07-07

最新評(píng)論

芜湖市| 马鞍山市| 门头沟区| 元谋县| 岳西县| 永福县| 丰宁| 三原县| 恩施市| 中山市| 清流县| 兖州市| 江安县| 凤庆县| 渭南市| 新乡县| 漳平市| 左贡县| 乡城县| 望城县| 庄河市| 德钦县| 莆田市| 江城| 清丰县| 双柏县| 冀州市| 会理县| 扎兰屯市| 象州县| 周至县| 博客| 巢湖市| 福海县| 如东县| 左云县| 沅江市| 宝丰县| 山丹县| 大关县| 黎城县|