欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

故事背景

故事發(fā)生在幾個(gè)星期前,自動(dòng)化平臺(tái)代碼開(kāi)放給整個(gè)測(cè)試團(tuán)隊(duì)以后,越來(lái)越多的同事開(kā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í)例一樣全部分開(kāi)搞一套,那在當(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開(kāi)發(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ī)制(推薦)

    詳解JAVA類加載機(jī)制(推薦)

    這篇文章主要介紹了JAVA類加載機(jī)制的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-09-09
  • Spring注解驅(qū)動(dòng)之ApplicationListener用法解讀

    Spring注解驅(qū)動(dòng)之ApplicationListener用法解讀

    這篇文章主要介紹了Spring注解驅(qū)動(dòng)之ApplicationListener用法解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • 詳解Spring中接口的bean是如何注入的

    詳解Spring中接口的bean是如何注入的

    這篇文章主要介紹了詳解Spring中接口的bean是如何注入的的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • SpringBoot+MyBatisPlus對(duì)Map中Date格式轉(zhuǎn)換處理的方法詳解

    SpringBoot+MyBatisPlus對(duì)Map中Date格式轉(zhuǎn)換處理的方法詳解

    在?SpringBoot?項(xiàng)目中,?如何統(tǒng)一?JSON?格式化中的日期格式。本文將為大家介紹一種方法:利用MyBatisPlus實(shí)現(xiàn)對(duì)Map中Date格式轉(zhuǎn)換處理,需要的可以參考一下
    2022-10-10
  • SpringBoot如何進(jìn)行對(duì)象復(fù)制的實(shí)踐

    SpringBoot如何進(jìn)行對(duì)象復(fù)制的實(shí)踐

    本文主要介紹了SpringBoot 如何進(jìn)行對(duì)象復(fù)制,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • springboot連接sqllite遇到的坑及解決

    springboot連接sqllite遇到的坑及解決

    這篇文章主要介紹了springboot連接sqllite遇到的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Springboot AOP對(duì)指定敏感字段數(shù)據(jù)加密存儲(chǔ)的實(shí)現(xiàn)

    Springboot AOP對(duì)指定敏感字段數(shù)據(jù)加密存儲(chǔ)的實(shí)現(xiàn)

    本篇文章主要介紹了利用Springboot+AOP對(duì)指定的敏感數(shù)據(jù)進(jìn)行加密存儲(chǔ)以及對(duì)數(shù)據(jù)中加密的數(shù)據(jù)的解密的方法,代碼詳細(xì),具有一定的價(jià)值,感興趣的小伙伴可以了解一下
    2021-11-11
  • Java使用泛型Class實(shí)現(xiàn)消除模板代碼

    Java使用泛型Class實(shí)現(xiàn)消除模板代碼

    Class作為實(shí)現(xiàn)反射功能的類,在開(kāi)發(fā)中經(jīng)常會(huì)用到,然而,當(dāng)Class遇上泛型后,事情就變得不是那么簡(jiǎn)單了,所以本文就來(lái)講講Java如何使用泛型Class實(shí)現(xiàn)消除模板代碼,需要的可以參考一下
    2023-06-06
  • JSP服務(wù)器端和前端出現(xiàn)亂碼問(wèn)題解決方案

    JSP服務(wù)器端和前端出現(xiàn)亂碼問(wèn)題解決方案

    這篇文章主要介紹了JSP服務(wù)器端和前端出現(xiàn)亂碼問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • springboot結(jié)合redis實(shí)現(xiàn)搜索欄熱搜功能及文字過(guò)濾

    springboot結(jié)合redis實(shí)現(xiàn)搜索欄熱搜功能及文字過(guò)濾

    本文主要介紹了springboot結(jié)合redis實(shí)現(xiàn)搜索欄熱搜功能及文字過(guò)濾,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02

最新評(píng)論