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

springboot注解之@Conditional使用解析

 更新時間:2023年11月27日 10:50:40   作者:碼農(nóng)打工人  
這篇文章主要介紹了springboot注解之@Conditional使用解析,conditional 這個英文單詞翻譯過來是有條件的,所以 @Conditional 注解是作為條件存在的,如果滿足配置的條件則執(zhí)行,如果沒有滿足的話就不執(zhí)行,需要的朋友可以參考下

前言

conditional 這個英文單詞翻譯過來是有條件的,所以 @Conditional 注解是作為條件存在的,如果滿足配置的條件則執(zhí)行,如果沒有滿足的話就不執(zhí)行。

一、@Conditional

@Conditional 注解上面說了是作為條件執(zhí)行的,那么是作為什么條件呢?這我們就需要知道 @Conditional 主要是作用在什么上面。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
    Class<? extends Condition>[] value();
}

上面是 @Conditional 注解的源碼。我們看到注解的作用域是類、方法上。既然是作用在類上,即可以大體猜測到與 IOC 容器添加 bean 有關(guān)系。 事實上 @Conditional 注解一般與 @Configuration、@Bean 共同使用,也可以與 @Controller、@Service、@Component、@Repository 等等這些注解一起使用。所以 @Conditional 通常是作為是否添加這個對象為 IOC 容器組件的條件出現(xiàn)的。 既然知道 @Conditional 注解的作用,那么該注解應(yīng)該如何使用呢?我們看到該注解有一個必填的屬性 value,value 屬性的類型是 Condition 接口的實現(xiàn)類數(shù)組。我們看下 Condition 接口的源碼。

@FunctionalInterface
public interface Condition {
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

Condition 接口只有一個抽象方法,返回 boolean 類型,可以知道返回為 true 則條件成立,返回 false 條件不成立。 方法中有兩個參數(shù),context 中包含容器、bean 工廠、類加載器、資源加載器、環(huán)境配置這五大核心屬性獲取方法,metadata 是注解的信息。 從這里我們也可以自己實現(xiàn) matches 方法,去自定義一個條件類。 自己去實現(xiàn) Condition 接口比較復(fù)雜,那么有沒有一些已經(jīng)實現(xiàn)好的常用的一些類呢?springboot 給我們提供了大量的這樣的實現(xiàn)類,讓我們基本不用自己去實現(xiàn) Condition 接口,就可以滿足日常的開發(fā)。

二、@Conditional 的實現(xiàn)子注解

springboot 提供了大量的 @Conditional 子注解供我們使用,我們只需知道有哪些常用的子注解供我們使用即可。

springboot 提供的 @Conditional 子注解有:

  1. @ConditionalOnBean
  2. @ConditionalOnClass
  3. @ConditionalOnCloudPlatform
  4. @ConditionalOnExpression
  5. @ConditionalOnJava
  6. @ConditionalOnJndi
  7. @ConditionalOnMissingBean
  8. @ConditionalOnMissingClass
  9. @ConditionalOnNotWebApplication
  10. @ConditionalOnProperty
  11. @ConditionalOnResource
  12. @ConditionalOnSingleCandidate
  13. @ConditionalOnWarDeployment
  14. @ConditionalOnWebApplication

這些子注解是如何實現(xiàn)的呢?我們以 @ConditionalOnBean 注解為例看下源碼:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({OnBeanCondition.class})
public @interface ConditionalOnBean {
    Class<?>[] value() default {};

    String[] type() default {};

    Class<? extends Annotation>[] annotation() default {};

    String[] name() default {};

    SearchStrategy search() default SearchStrategy.ALL;

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

可以看到 OnBeanCondition 是 Condition 接口的具體實現(xiàn)類。 我們挑選一些日常常用的子注解做具體的說明。

三、@ConditionalOnClass 注解

@ConditionalOnClass 的意思是以是否有該類為為條件。我們以 springboot 自動配置 aop 的配置類做例子進行解讀。 我們打開 springboot 的自動配置包 spring-boot-autoconfigure-2.7.0.jar 包,找到 AopAutoConfiguration.class,打開后有這么一段代碼。

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({Advice.class})
static class AspectJAutoProxyingConfiguration {
    AspectJAutoProxyingConfiguration() {
    }

    @Configuration(
        proxyBeanMethods = false
    )
    @EnableAspectJAutoProxy(
        proxyTargetClass = true
    )
    @ConditionalOnProperty(
        prefix = "spring.aop",
        name = {"proxy-target-class"},
        havingValue = "true",
        matchIfMissing = true
    )
    static class CglibAutoProxyConfiguration {
        CglibAutoProxyConfiguration() {
        }
    }

    @Configuration(
        proxyBeanMethods = false
    )
    @EnableAspectJAutoProxy(
        proxyTargetClass = false
    )
    @ConditionalOnProperty(
        prefix = "spring.aop",
        name = {"proxy-target-class"},
        havingValue = "false"
    )
    static class JdkDynamicAutoProxyConfiguration {
        JdkDynamicAutoProxyConfiguration() {
        }
    }
}

我們看到在內(nèi)部類 AspectJAutoProxyingConfiguration 上標注了 @ConditionalOnClass({Advice.class}) 表示如果有 Advice.class 這個類則 AspectJAutoProxyingConfiguration 生效,否則就不生效。

那么我們測試以下。 首先我們測試以下沒有的時候。

@SpringBootApplication
public class SpringbootFunctionApplication {

    public static void main(String[] args) {
        // 返回 IOC 容器
        ConfigurableApplicationContext run = SpringApplication.run(SpringbootFunctionApplication.class, args);
        // 測試沒有 Advice.class 的時候,是否有 AspectJAutoProxyingConfiguration 組件
        try {
            // 反射獲取內(nèi)部類的 Class 對象
            Class<?> clazz = Class.forName("org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$AspectJAutoProxyingConfiguration");
            System.out.println(MessageFormat.format("容器中 AspectJAutoProxyingConfiguration 類型的組件個數(shù)有:{0}", run.getBeanNamesForType(clazz).length));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

結(jié)果為:

容器中 AspectJAutoProxyingConfiguration 類型的組件個數(shù)有:0

可以看到如果沒有 Advice.class 的時候,@ConditionalOnClass 標簽做了攔截,沒有添加 AspectJAutoProxyingConfiguration 為組件。

我們看下如果導(dǎo)入 Advice.class 之后會有什么現(xiàn)象。

我們在 pom 文件中導(dǎo)入 aspectj 依賴

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.19</version>
    <scope>runtime</scope>
</dependency>

最后執(zhí)行我們看到的結(jié)果為:

容器中 AspectJAutoProxyingConfiguration 類型的組件個數(shù)有:1

可以看到有了 Advice.class 之后,在容器添加 AspectJAutoProxyingConfiguration 作為 bean 的時候,通過了 @ConditionalOnClass 的校驗。

四、@ConditionalOnMissingClass 注解

我們說完了 @ConditionalOnClass,我們說一下它的相反意思的注解:@ConditionalOnMissingClass。 @ConditionalOnMissingClass 是如果沒有這個 class 類則執(zhí)行。我們同樣以 springboot 自動配置 aop 的配置類做例子,不同的是我們選擇了 AopAutoConfiguration.class 中的另一個內(nèi)部類 ClassProxyingConfiguration。

@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass({"org.aspectj.weaver.Advice"})
@ConditionalOnProperty(
    prefix = "spring.aop",
    name = {"proxy-target-class"},
    havingValue = "true",
    matchIfMissing = true
)
static class ClassProxyingConfiguration {
    ClassProxyingConfiguration() {
    }

    @Bean
    static BeanFactoryPostProcessor forceAutoProxyCreatorToUseClassProxying() {
        return (beanFactory) -> {
            if (beanFactory instanceof BeanDefinitionRegistry) {
                BeanDefinitionRegistry registry = (BeanDefinitionRegistry)beanFactory;
                AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }

        };
    }
}

可以看到內(nèi)部類 ClassProxyingConfiguration 上面標注了 @ConditionalOnMissingClass 標簽,條件是 org.aspectj.weaver.Advice 字符串,代表沒有該類則通過。

上面已經(jīng)引入了 aspectjweaver jar 包,我們看看容器中有沒有 ClassProxyingConfiguration 這個 bean。

@SpringBootApplication
public class SpringbootFunctionApplication {

    public static void main(String[] args) {
        // 返回 IOC 容器
        ConfigurableApplicationContext run = SpringApplication.run(SpringbootFunctionApplication.class, args);
        // 測試有 Advice.class 的時候,是否有 ClassProxyingConfiguration 組件
        try {
            Class<?> clazz = Class.forName("org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$ClassProxyingConfiguration");
            System.out.println(MessageFormat.format("容器中 ClassProxyingConfiguration 類型的組件個數(shù)有:{0}", run.getBeanNamesForType(clazz).length));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

}

結(jié)果為:

容器中 ClassProxyingConfiguration 類型的組件個數(shù)有:0

可以看出有 Advice.class 的時候 @ConditionalOnMissingClass 注解會判斷不通過,不會注冊 ClassProxyingConfiguration 為 bean。

反過來如果沒有 Advice.class 的時候會是什么樣子呢?

容器中 ClassProxyingConfiguration 類型的組件個數(shù)有:1

五、@ConditionalOnBean 與 @ConditionalOnMissingBean

上面我們看了注解 @ConditionalOnClass、@ConditionalOnMissingClass,我們將要看的注解 @ConditionalOnBean 與 @ConditionalOnMissingBean 其實意思也是相似的,只不過前兩個注解以是否有 class 類作為判斷條件,后兩個注解以容器中是否有組件 bean 作為判斷條件。 我們看一個例子

@Bean
@ConditionalOnBean({MultipartResolver.class})
@ConditionalOnMissingBean(name = {"multipartResolver"})
public MultipartResolver multipartResolver(MultipartResolver resolver) {
    return resolver;
}

這里 @ConditionalOnBean({MultipartResolver.class}) 如果容器中有 MultipartResolver 類型的 bean 則條件通過。 @ConditionalOnMissingBean(name = {“multipartResolver”}) 則表示如果容器中沒有 ID 為 multipartResolver 的 bean 則條件通過。 可以看出這段代碼的功能是,如果容器中有 MultipartResolver 這個類型的 bean 但 ID 名稱不是 multipartResolver,則把名稱改為 multipartResolver。

六、@ConditionalOnProperty 注解

@ConditionalOnProperty 注解是以項目中的配置作為條件確定是否注冊為 bean。 我們還是以 springboot 自動配置 aop 的配置類 AopAutoConfiguration.class 中的子類 AspectJAutoProxyingConfiguration 做例子進行解讀。

static class AspectJAutoProxyingConfiguration {
        AspectJAutoProxyingConfiguration() {
        }

        @Configuration(
            proxyBeanMethods = false
        )
        @EnableAspectJAutoProxy(
            proxyTargetClass = true
        )
        @ConditionalOnProperty(
            prefix = "spring.aop",
            name = {"proxy-target-class"},
            havingValue = "true",
            matchIfMissing = true
        )
        static class CglibAutoProxyConfiguration {
            CglibAutoProxyConfiguration() {
            }
        }

        @Configuration(
            proxyBeanMethods = false
        )
        @EnableAspectJAutoProxy(
            proxyTargetClass = false
        )
        @ConditionalOnProperty(
            prefix = "spring.aop",
            name = {"proxy-target-class"},
            havingValue = "false"
        )
        static class JdkDynamicAutoProxyConfiguration {
            JdkDynamicAutoProxyConfiguration() {
            }
        }
    }

可以看到 @ConditionalOnProperty 注解具有4個屬性 prefix(配置前綴)、name(配置名稱)、havingValue(匹配的值)、matchIfMissing(如果找不到這個配置的值則返回) 在 AspectJAutoProxyingConfiguration 中有兩個內(nèi)部類 CglibAutoProxyConfiguration、JdkDynamicAutoProxyConfiguration。 CglibAutoProxyConfiguration 上面標注的注解 @ConditionalOnProperty 屬性匹配的值為 true,如果沒有該配置則默認通過。 JdkDynamicAutoProxyConfiguration 上面標注的注解 @ConditionalOnProperty 屬性匹配的值為 false,沒有 matchIfMissing 屬性。 我們進行下面測試:

@SpringBootApplication(scanBasePackages = {"com.study.springbootfunction", "com.study.exclude"})
public class SpringbootFunctionApplication {

    public static void main(String[] args) {
        // 返回 IOC 容器
        ConfigurableApplicationContext run = SpringApplication.run(SpringbootFunctionApplication.class, args);
        // 是否包含 CglibAutoProxyConfiguration、JdkDynamicAutoProxyConfiguration
        try {
            Class<?> a = Class.forName("org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$AspectJAutoProxyingConfiguration$CglibAutoProxyConfiguration");
            Class<?> j = Class.forName("org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$AspectJAutoProxyingConfiguration$JdkDynamicAutoProxyConfiguration");
            System.out.println(MessageFormat.format("容器中 CglibAutoProxyConfiguration 類型的組件個數(shù)有:{0}", run.getBeanNamesForType(a).length));
            System.out.println(MessageFormat.format("容器中 JdkDynamicAutoProxyConfiguration 類型的組件個數(shù)有:{0}", run.getBeanNamesForType(j).length));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

先不在項目中配置 spring.aop.proxy-target-class 運行結(jié)果為:

容器中 CglibAutoProxyConfiguration 類型的組件個數(shù)有:1
容器中 JdkDynamicAutoProxyConfiguration 類型的組件個數(shù)有:0

能夠得出 如果屬性 matchIfMissing 不配置的話默認為 false。 在項目中配置 spring.aop.proxy-target-class=true

spring:
  aop:
    proxy-target-class: true

運行結(jié)果為:

容器中 CglibAutoProxyConfiguration 類型的組件個數(shù)有:1
容器中 JdkDynamicAutoProxyConfiguration 類型的組件個數(shù)有:0

如果在項目中配置 spring.aop.proxy-target-class=false

spring:
  aop:
    proxy-target-class: false

運行結(jié)果為:

容器中 CglibAutoProxyConfiguration 類型的組件個數(shù)有:0
容器中 JdkDynamicAutoProxyConfiguration 類型的組件個數(shù)有:1

可以看出 @ConditionalOnProperty 屬性 havingValue 的值與項目中配置的值相匹配時為滿足條件,如果值不匹配的時候則條件不滿足。

七、@ConditionalOnWebApplication

如果是 web 應(yīng)用,則滿足條件。這個配置在 mvc 中的配置比較多,我們看下 mvc 中 DispatcherServlet 的自動配置類。

@AutoConfigureOrder(-2147483648)
@AutoConfiguration(
    after = {ServletWebServerFactoryAutoConfiguration.class}
)
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({DispatcherServlet.class})
public class DispatcherServletAutoConfiguration {
}

我們看到 DispatcherServletAutoConfiguration 在是 servlet 的傳統(tǒng)項目中則成立,滿足條件。

到此這篇關(guān)于springboot注解之@Conditional使用解析的文章就介紹到這了,更多相關(guān)springboot注解@Conditional內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springboot2自動加載sql文件的實現(xiàn)

    springboot2自動加載sql文件的實現(xiàn)

    本文主要介紹了springboot2自動加載sql文件的實現(xiàn),通過配置文件或注解的方式,我們可以輕松地將SQL語句映射到數(shù)據(jù)庫中,實現(xiàn)自動加載,感興趣的可以了解一下
    2023-11-11
  • 深層剖析java應(yīng)用開發(fā)中MyBayis緩存

    深層剖析java應(yīng)用開發(fā)中MyBayis緩存

    這篇文章主要為大家深層剖析java開發(fā)中MyBayis緩存,文中講解了Mybatis緩存的分類以及使用的方式,有需要的朋友可以借鑒參考下,希望可以有所幫助
    2021-09-09
  • 關(guān)于webLucene 安裝方法

    關(guān)于webLucene 安裝方法

    webLucene是一個基于開源項目lucene實現(xiàn)站內(nèi)搜索的工具,關(guān)于它的安裝,百度得到的大多是一樣的,按照步驟也能正確安裝并運行,需要注意的問題是
    2009-06-06
  • Spring?MVC中@Controller和@RequestMapping注解使用

    Spring?MVC中@Controller和@RequestMapping注解使用

    這篇文章主要介紹了Spring?MVC中@Controller和@RequestMapping注解使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • Java實現(xiàn)多線程文件下載的代碼示例

    Java實現(xiàn)多線程文件下載的代碼示例

    本篇文章主要介紹了Java實現(xiàn)多線程下載的代碼示例,Java多線程可以充分利用CPU的資源,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-02-02
  • Java 異常詳解

    Java 異常詳解

    本文主要介紹了異常與錯誤的區(qū)別,異常的體現(xiàn)分類,異常的處理機制,如何自定義異常等,具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02
  • SpringCloud Config分布式配置中心使用教程介紹

    SpringCloud Config分布式配置中心使用教程介紹

    springcloud config是一個解決分布式系統(tǒng)的配置管理方案。它包含了 client和server兩個部分,server端提供配置文件的存儲、以接口的形式將配置文件的內(nèi)容提供出去,client端通過接口獲取數(shù)據(jù)、并依據(jù)此數(shù)據(jù)初始化自己的應(yīng)用
    2022-12-12
  • Java并發(fā)編程之工具類Semaphore的使用

    Java并發(fā)編程之工具類Semaphore的使用

    目前幾乎所有的語言都支持信號量機制,Java也不例外.Java中提供了Semaphore并發(fā)工具類來支持信號量機制,下面我們就來了解Java實現(xiàn)的信號量機制,文中有非常詳細的介紹,需要的朋友可以參考下
    2021-06-06
  • TCP/IP協(xié)議中三次握手四次揮手的原理及流程分析

    TCP/IP協(xié)議中三次握手四次揮手的原理及流程分析

    這篇文章主要介紹了TCP/IP協(xié)議中三次握手四次揮手的原理及流程分析,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11
  • SpringBoot整合Caffeine使用示例

    SpringBoot整合Caffeine使用示例

    Spring Boot 和 Caffeine 可以很容易地進行整合,Caffeine 是一個現(xiàn)代化的 Java 緩存庫,提供了高性能和靈活的緩存策略,本文給大家介紹了SpringBoot整合Caffeine使用示例,需要的朋友可以參考下
    2024-07-07

最新評論