1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Spring Boot 條件注解

        共 9783字,需瀏覽 20分鐘

         ·

        2022-01-02 14:42

        ?SpringBoot條件注解@Conditional,可用于根據(jù)某個(gè)特定的條件來(lái)判斷是否需要?jiǎng)?chuàng)建某個(gè)特定的Bean。SpringBoot自動(dòng)配置功能里面就大量的使用了條件注解。接下來(lái)我們就對(duì)@Conditional的使用做一個(gè)簡(jiǎn)單的介紹。

        ? ? ? ?@Conditional注解需要和Condition接口搭配一起使用。通過(guò)對(duì)應(yīng)Condition接口來(lái)告知是否滿(mǎn)足匹配條件。


        @Target({ElementType.TYPE,?ElementType.METHOD})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        public?@interface?Conditional?{

        ????/**
        ?????*?所有用于匹配的Condition接口(實(shí)現(xiàn)該接口的類(lèi)),只有這些類(lèi)都返回true才認(rèn)為是滿(mǎn)足條件
        ?????*/

        ????Classextends
        ?Condition>[]?value();

        }


        ? ? ? ?@Conditional注解可以添加在@Configuration、@Component、@Service等修飾的類(lèi)上用于控制對(duì)應(yīng)的Bean是否需要?jiǎng)?chuàng)建,或者添加在@Bean修飾的方法上用于控制方法對(duì)應(yīng)的Bean是否需要?jiǎng)?chuàng)建。

        @Conditional添加在@Configuration修飾的類(lèi)上,用于控制該類(lèi)和該類(lèi)里面所有添加的@Bean方法對(duì)應(yīng)的Bean是否需要?jiǎng)?chuàng)建。

        一 @Conditional擴(kuò)展注解

        ? ? ? ?為了方便我們的使用Spring Boot對(duì)@Conditional條件注解做了一些擴(kuò)展,提供了一些很實(shí)用的擴(kuò)展性條件注解。

        條件注解Condition處理類(lèi)實(shí)例解釋
        @ConditionalOnBeanOnBeanCondition@ConditionalOnBean(DataSource.class)Spring容器中不存在對(duì)應(yīng)的實(shí)例生效
        @ConditionalOnMissingBeanOnBeanCondition@ConditionalOnMissingBean(name = "redisTemplate")Spring容器中不存在對(duì)應(yīng)的實(shí)例生效
        @ConditionalOnSingleCandidateOnBeanCondition@ConditionalOnSingleCandidate(FilteringNotifier.class)Spring容器中是否存在且只存在一個(gè)對(duì)應(yīng)的實(shí)例,或者雖然有多個(gè)但 是指定首選的Bean生效
        @ConditionalOnClassOnClassCondition@ConditionalOnClass(RedisOperations.class)類(lèi)加載器中存在對(duì)應(yīng)的類(lèi)生效
        @ConditionalOnMissingClassOnClassCondition@ConditionalOnMissingClass(RedisOperations.class)類(lèi)加載器中不存在對(duì)應(yīng)的類(lèi)生效
        @ConditionalOnExpressionOnExpressionCondition@ConditionalOnExpression(“’${server.host}’==’localhost’”)判斷SpEL 表達(dá)式成立生效
        @ConditionalOnJavaOnJavaCondition@ConditionalOnJava(JavaVersion.EIGHT)指定Java版本符合要求生效
        @ConditionalOnPropertyOnPropertyCondition@ConditionalOnProperty(prefix = “spring.aop”, name = “auto”, havingValue = “true”, matchIfMissing = true)應(yīng)用環(huán)境中的屬性滿(mǎn)足條件生效
        @ConditionalOnResourceOnResourceCondition@ConditionalOnResource(resources=”mybatis.xml”)存在指定的資源文件生效
        @ConditionalOnWebApplicationOnWebApplicationCondition
        當(dāng)前應(yīng)用是Web應(yīng)用生效
        @ConditionalOnNotWebApplicationOnWebApplicationCondition
        當(dāng)前應(yīng)用不是Web應(yīng)用生效

        ? ? ? ?上面的擴(kuò)展注解我們可以簡(jiǎn)單的分為以下幾類(lèi):

        • Bean作為條件:@ConditionalOnBean、@ConditionalOnMissingBean、@ConditionalOnSingleCandidate。

        • 類(lèi)作為條件:@ConditionalOnClass、@ConditionalOnMissingClass。

        • SpEL表達(dá)式作為條件:@ConditionalOnExpression。

        • JAVA版本作為條件: @ConditionalOnJava

        • 配置屬性作為條件:@ConditionalOnProperty。

        • 資源文件作為條件:@ConditionalOnResource。

        • 是否Web應(yīng)用作為判斷條件:@ConditionalOnWebApplication、@ConditionalOnNotWebApplication。

        1.1 Bean作為條件

        1.1.1 @ConditionalOnBean

        ? ? ? ?@ConditionalOnBean對(duì)應(yīng)的Condition處理類(lèi)是OnBeanCondition。如果Spring容器里面存在指定的Bean則生效。

        @ConditionalOnBean配置參數(shù)

        @Target({?ElementType.TYPE,?ElementType.METHOD?})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @Conditional(OnBeanCondition.class)
        public?@interface?ConditionalOnBean?{

        ????/**
        ?????*?需要作為條件的類(lèi)的Class對(duì)象數(shù)組
        ?????*/

        ????Class[]?value()?default?{};

        ????/**
        ?????*?需要作為條件的類(lèi)的Name,?Class.getName()
        ?????*/

        ????String[]?type()?default?{};

        ????/**
        ?????*?(用于指定注解修飾的Bean)條件所需的注解類(lèi)
        ?????*/

        ????Classextends
        ?Annotation>[]?annotation()?default?{};

        ????/**
        ?????*?Spring容器中Bean的名字
        ?????*/

        ????String[]?name()?default?{};

        ????/**
        ?????*?搜索容器層級(jí),當(dāng)前容器,父容器
        ?????*/

        ????SearchStrategy?search()?default?SearchStrategy.ALL;

        ????/**
        ?????*?可能在其泛型參數(shù)中包含指定Bean類(lèi)型的其他類(lèi)
        ?????*/

        ????Class[]?parameterizedContainer()?default?{};

        }


        1.1.2 @ConditionalOnMissingBean

        ? ? ? ?@ConditionalOnMissingBean對(duì)應(yīng)的Condition實(shí)現(xiàn)類(lèi)是OnBeanCondition。如果Spring容器里面不存在指定的Bean則生效。

        @ConditionalOnMissingBean配置參數(shù)


        @Target({?ElementType.TYPE,?ElementType.METHOD?})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @Conditional(OnBeanCondition.class)
        public?@interface?ConditionalOnMissingBean?{

        ????/**
        ?????*?需要作為條件的類(lèi)的Class對(duì)象數(shù)組
        ?????*/

        ????Class[]?value()?default?{};

        ????/**
        ?????*?需要作為條件的類(lèi)的Name,?Class.getName()
        ?????*/

        ????String[]?type()?default?{};

        ????/**
        ?????*?匹配Bean的時(shí)候需要忽視的Class對(duì)象數(shù)組,一般是父類(lèi)
        ?????*?@ConditionalOnMissingBean(value?=?JdbcFactory.class,?ignored?=?MySqlDefaultFactory.class)
        ?????*/

        ????Class[]?ignored()?default?{};

        ????/**
        ?????*?匹配Bean的時(shí)候需要忽視的類(lèi)的Name,?Class.getName()
        ?????*/

        ????String[]?ignoredType()?default?{};

        ????/**
        ?????*?(用于指定注解修飾的Bean)條件所需的注解類(lèi)
        ?????*/

        ????Classextends
        ?Annotation>[]?annotation()?default?{};

        ????/**
        ?????*?Spring容器中Bean的名字
        ?????*/

        ????String[]?name()?default?{};

        ????/**
        ?????*?搜索容器層級(jí),當(dāng)前容器,父容器
        ?????*/

        ????SearchStrategy?search()?default?SearchStrategy.ALL;

        ????/**
        ?????*?可能在其泛型參數(shù)中包含指定Bean類(lèi)型的其他類(lèi)
        ?????*/

        ????Class[]?parameterizedContainer()?default?{};

        }



        ? ? ? ?比如如下的實(shí)例,當(dāng)容器里面不存在redisTemplate對(duì)應(yīng)的Bean的時(shí)候,就會(huì)創(chuàng)建一個(gè)RedisTemplate添加到容器里面去。


        @Bean
        ????@ConditionalOnMissingBean(name?=?"redisTemplate")
        ????public?RedisTemplate<Object,?Object>?redisTemplate(RedisConnectionFactory?redisConnectionFactory)
        ????????????throws?UnknownHostException?{
        ????????RedisTemplate<Object,?Object>?template?=?new?RedisTemplate<>();
        ????????template.setConnectionFactory(redisConnectionFactory);
        ????????return?template;
        ????}


        1.1.3 @ConditionalOnSingleCandidate

        ? ? ? ?@ConditionalOnSingleCandidate對(duì)應(yīng)的Condition處理類(lèi)是OnBeanCondition。如果當(dāng)指定Bean在容器中只有一個(gè),或者雖然有多個(gè)但是指定首選Bean的時(shí)候則生效。

        @ConditionalOnSingleCandidate配置參數(shù)


        @Target({?ElementType.TYPE,?ElementType.METHOD?})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @Conditional(OnBeanCondition.class)
        public?@interface?ConditionalOnSingleCandidate?{

        ????/**
        ?????*?需要作為條件的類(lèi)的Class對(duì)象
        ?????*/

        ????Class?value()?default?Object.class;

        ????/**
        ?????*?需要作為條件的類(lèi)的Name,?Class.getName()
        ?????*/

        ????String?type()?default?"";

        ????/**
        ?????*?搜索容器層級(jí),當(dāng)前容器,父容器
        ?????*/

        ????SearchStrategy?search()?default?SearchStrategy.ALL;

        }


        1.2 類(lèi)作為條件

        1.2.1 @ConditionalOnClass

        ? ? ? ?@ConditionalOnClass對(duì)應(yīng)的Condition處理類(lèi)是OnClassCondition。如果當(dāng)前類(lèi)路徑下面有指定的類(lèi)的時(shí)候則生效。

        @ConditionalOnClass配置屬性介紹


        @Target({?ElementType.TYPE,?ElementType.METHOD?})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @Conditional(OnClassCondition.class)
        public?@interface?ConditionalOnClass?{

        ????/**
        ?????*?需要作為條件的類(lèi)的Class對(duì)象數(shù)組
        ?????*/

        ????Class[]?value()?default?{};

        ????/**
        ?????*?需要作為條件的類(lèi)的Name,?Class.getName()
        ?????*/

        ????String[]?name()?default?{};

        }



        1.2.2 @ConditionalOnMissingClass

        ? ? ? ?@ConditionalOnMissingClass對(duì)應(yīng)的Condition處理類(lèi)是OnClassCondition。如果當(dāng)前類(lèi)路徑下面沒(méi)有指定的類(lèi)的時(shí)候則生效。


        @Target({?ElementType.TYPE,?ElementType.METHOD?})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @Conditional(OnClassCondition.class)
        public?@interface?ConditionalOnMissingClass?{

        ????/**
        ?????*?需要作為條件的類(lèi)的Name,?Class.getName()
        ?????*/

        ????String[]?value()?default?{};

        }



        1.3 ?SpEL表達(dá)式作為條件

        ? ? ? ?@ConditionalOnExpression對(duì)應(yīng)的Condition處理類(lèi)是OnExpressionCondition。只有當(dāng)SpEL表達(dá)式滿(mǎn)足條件的時(shí)候則生效。


        @Retention(RetentionPolicy.RUNTIME)
        @Target({?ElementType.TYPE,?ElementType.METHOD?})
        @Documented
        @Conditional(OnExpressionCondition.class)
        public?@interface?ConditionalOnExpression?{

        ????/**
        ?????*?要作為條件的SpEL表達(dá)式
        ?????*/

        ????String?value()?default?"true";

        }


        ? ? ? ?例如@ConditionalOnExpression("${test.enabled:true}"),只有當(dāng)配置文件里面存在test.enabled: true的時(shí)候則生效。

        更加詳細(xì)的用法可以去看下SpEL表達(dá)式的使用。

        1.4 ?JAVA版本作為判斷條件

        ? ? ? ?@ConditionalOnJava對(duì)應(yīng)的Condition處理類(lèi)是OnJavaCondition。只有當(dāng)指定的JAVA版本條件滿(mǎn)足的時(shí)候,才會(huì)創(chuàng)建對(duì)應(yīng)的Bean。


        @Target({?ElementType.TYPE,?ElementType.METHOD?})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @Conditional(OnJavaCondition.class)
        public?@interface?ConditionalOnJava?{

        ????/**
        ?????*?比較方式,Range.EQUAL_OR_NEWER:當(dāng)前版本等于或高于、Range.OLDER_THAN:當(dāng)前版本老于,越早的版本越老
        ?????*/

        ????Range?range()?default?Range.EQUAL_OR_NEWER;

        ????/**
        ?????*?指定JAVA版本
        ?????*/

        ????JavaVersion?value();

        ????/**
        ?????*?Range?options.
        ?????*/

        ????enum?Range?{

        ????????/**
        ?????????*?Equal?to,?or?newer?than?the?specified?{@link?JavaVersion}.
        ?????????*/

        ????????EQUAL_OR_NEWER,

        ????????/**
        ?????????*?Older?than?the?specified?{@link?JavaVersion}.
        ?????????*/

        ????????OLDER_THAN

        ????}

        }


        1.5 配置屬性作為判斷條件

        ? ? ? ?@ConditionalOnProperty對(duì)應(yīng)的Condition實(shí)現(xiàn)類(lèi)OnPropertyCondition。只有當(dāng)對(duì)應(yīng)的配置屬性和給定條件的值相等的時(shí)候則生效。


        @Retention(RetentionPolicy.RUNTIME)
        @Target({?ElementType.TYPE,?ElementType.METHOD?})
        @Documented
        @Conditional(OnPropertyCondition.class)
        public?@interface?ConditionalOnProperty?{

        ????/**
        ?????*?對(duì)應(yīng)property名稱(chēng)的值
        ?????*/
        ????String[]?value()?default?{};
        ????String[]?name()?default?{};


        ????/**
        ?????*?property名稱(chēng)的前綴,可有可無(wú)
        ?????*/
        ????String?prefix()?default?"";

        ????/**
        ?????*?與name組合使用,比較獲取到的屬性值與havingValue給定的值是否相同,相同才加載配置
        ?????*/
        ????String?havingValue()?default?"";

        ????/**
        ?????*?缺少該property時(shí)是否可以加載。如果為true,沒(méi)有該property也會(huì)正常加載;反之報(bào)錯(cuò)
        ?????*/
        ????boolean?matchIfMissing()?default?false;

        }


        ? ? ? ?@ConditionalOnProperty(prefix = “spring.aop”, name = “auto”, havingValue = “true”)表示當(dāng)配置文件里面spring.aop.auto=true的時(shí)候才會(huì)加載對(duì)應(yīng)的Bean。

        1.6 資源文件是否存在作為判斷條件

        ? ? ? ?@ConditionalOnResource對(duì)應(yīng)的Condition處理類(lèi)OnResourceCondition。只有當(dāng)指定的資源文件出現(xiàn)在classpath中則生效。

        @ConditionalOnResource配置屬性


        @Target({?ElementType.TYPE,?ElementType.METHOD?})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @Conditional(OnResourceCondition.class)
        public?@interface?ConditionalOnResource?{

        ????/**
        ?????*?要作為判斷條件的資源文件名稱(chēng)??@ConditionalOnResource(resources=”mybatis.xml”)
        ?????*/

        ????String[]?resources()?default?{};

        }



        1.7 是否Web應(yīng)用作為判斷條件

        1.7.1 @ConditionalOnWebApplication

        ? ? ? ?@ConditionalOnWebApplication對(duì)應(yīng)的Condition處理類(lèi)是OnWebApplicationCondition。只有當(dāng)當(dāng)前項(xiàng)目是Web項(xiàng)目的時(shí)候則生效。


        @Target({?ElementType.TYPE,?ElementType.METHOD?})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @Conditional(OnWebApplicationCondition.class)
        public?@interface?ConditionalOnWebApplication?{

        ????/**
        ?????*?需要作為條件的Web應(yīng)用程序的必需類(lèi)型
        ?????*/

        ????Type?type()?default?Type.ANY;

        ????/**
        ?????*?Available?application?types.
        ?????*/

        ????enum?Type?{

        ????????/**
        ?????????*?任何web應(yīng)用都將匹配
        ?????????*/

        ????????ANY,

        ????????/**
        ?????????*?僅基于servlet的Web應(yīng)用程序?qū)⑵ヅ?br>?????????*/

        ????????SERVLET,

        ????????/**
        ?????????*?僅基于反應(yīng)式的Web應(yīng)用程序?qū)⑵ヅ?br>?????????*/

        ????????REACTIVE

        ????}

        }


        1.7.2 @ConditionalOnNotWebApplication

        ? ? ? ?@ConditionalOnNotWebApplication對(duì)應(yīng)的Condition處理類(lèi)是OnWebApplicationCondition。只有當(dāng)當(dāng)前項(xiàng)目不是Web項(xiàng)目的時(shí)候則生效。


        @Target({?ElementType.TYPE,?ElementType.METHOD?})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @Conditional(OnWebApplicationCondition.class)
        public?@interface?ConditionalOnNotWebApplication?{

        }


        二 @Conditional自定義

        ? ? ? ?上面介紹每個(gè)擴(kuò)展注解的時(shí)候都特意提到了每個(gè)注解對(duì)應(yīng)的Condition實(shí)現(xiàn)類(lèi)。其實(shí)我們可以仿照這些Condition實(shí)現(xiàn)類(lèi)來(lái)實(shí)現(xiàn)我們自己的@Conditional注解。下面我們同個(gè)兩個(gè)簡(jiǎn)單的實(shí)例來(lái)看下怎么實(shí)現(xiàn)自己的@Conditional擴(kuò)展注解。

        2.1 判斷是否配置指定屬性

        ? ? ? ?注意,和@ConditionalOnProperty不一樣哦,@ConditionalOnProperty是判斷是否有屬性并且判斷值是否等于我們指定的值。我們要實(shí)現(xiàn)的注解只判斷有沒(méi)有配置屬性,不管屬性對(duì)應(yīng)的值。

        ? ? ? ?擴(kuò)展注解ConditionalOnPropertyExist。指定我們的Condition實(shí)現(xiàn)類(lèi)OnPropertyExistCondition。并且指定兩個(gè)參數(shù)。一個(gè)是參數(shù)name用于指定屬性。另一個(gè)參數(shù)exist用于指定是判斷存在還是不存在。


        @Retention(RetentionPolicy.RUNTIME)
        @Target({ElementType.TYPE,?ElementType.METHOD})
        @Documented
        @Conditional(OnPropertyExistCondition.class)
        public?@interface?ConditionalOnPropertyExist?{

        ????/**
        ?????*?配置文件里面對(duì)應(yīng)的key
        ?????*/

        ????String?name()?default?"";

        ????/**
        ?????*?是否有配置的時(shí)候判斷通過(guò)
        ?????*/

        ????boolean?exist()?default?true;

        }


        ? ? ? ?OnPropertyExistCondition類(lèi)就是簡(jiǎn)單的判斷下屬性存在與否。


        public?class?OnPropertyExistCondition?implements?Condition?{
        ????@Override
        ????public?boolean?matches(ConditionContext?conditionContext,?AnnotatedTypeMetadata?annotatedTypeMetadata)?{
        ????????Map<String,?Object>?annotationAttributes?=?annotatedTypeMetadata.getAnnotationAttributes(ConditionalOnPropertyExist.class.getName());
        ????????if?(annotationAttributes?==?null)?{
        ????????????return?false;
        ????????}
        ????????String?propertyName?=?(String)?annotationAttributes.get("name");
        ????????boolean?values?=?(boolean)?annotationAttributes.get("exist");
        ????????String?propertyValue?=?conditionContext.getEnvironment().getProperty(propertyName);
        ????????if(values)?{
        ????????????return?!StringUtils.isEmpty(propertyValue);
        ????????}?else?{
        ????????????return?StringUtils.isEmpty(propertyValue);
        ????????}
        ????}
        }


        2.1 判斷是否配置指定屬性

        ? ? ? ?我們簡(jiǎn)單實(shí)現(xiàn)這樣一個(gè)功能,根據(jù)指定的系統(tǒng)加載不同的Bean。


        @Retention(RetentionPolicy.RUNTIME)
        @Target({ElementType.TYPE,?ElementType.METHOD})
        @Documented
        @Conditional(OnSystemCondition.class)
        public?@interface?ConditionalOnSystem?{

        ????/**
        ?????*?指定系統(tǒng)
        ?????*/

        ????SystemType?type()?default?SystemType.WINDOWS;

        ????/**
        ?????*?系統(tǒng)類(lèi)型
        ?????*/

        ????enum?SystemType?{

        ????????/**
        ?????????*?windows系統(tǒng)
        ?????????*/

        ????????WINDOWS,

        ????????/**
        ?????????*?linux系統(tǒng)
        ?????????*/

        ????????LINUX,

        ????????/**
        ?????????*?mac系統(tǒng)
        ?????????*/

        ????????MAC

        ????}
        }
        public?class?OnSystemCondition?implements?Condition?{


        ????@Override
        ????public?boolean?matches(ConditionContext?context,?AnnotatedTypeMetadata?metadata)?{
        ????????Map<String,?Object>?annotationAttributes?=?metadata.getAnnotationAttributes(ConditionalOnSystem.class.getName());
        ????????if?(annotationAttributes?==?null)?{
        ????????????return?false;
        ????????}
        ????????ConditionalOnSystem.SystemType?systemType?=?(ConditionalOnSystem.SystemType)?annotationAttributes.get("type");
        ????????switch?(systemType)?{
        ????????????case?WINDOWS:
        ????????????????return?context.getEnvironment().getProperty("os.name").contains("Windows");
        ????????????case?LINUX:
        ????????????????return?context.getEnvironment().getProperty("os.name").contains("Linux?");
        ????????????case?MAC:
        ????????????????return?context.getEnvironment().getProperty("os.name").contains("Mac?");
        ????????}
        ????????return?false;
        ????}
        }


        作者:tuacy
        source:?//www.jianshu.com/p/e21b9079a23c

        喜歡,在看

        瀏覽 46
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            一区二区三区无码播放 | 免费 无码 精品 国产76在线 | 撩起老师旗袍挺进去玉足视频 | 国产精品片www48888 | 女人让男人操 | 想看操逼| 久热免费在线观看 | 亚洲精品网站3d动漫之医院 | 久久久久成人精品无码中文字幕 | 男人爽女人下面动态图 |