亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring框架中的@Conditional系列注解詳解

 更新時(shí)間:2024年01月03日 09:32:37   作者:趙廣陸  
這篇文章主要介紹了Spring框架中的@Conditional系列注解詳解,我們需要一個(gè)類(lèi)實(shí)現(xiàn)Spring提供的Condition接口,它會(huì)匹配@Conditional所符合的方法,然后我們可以使用我們?cè)贎Conditional注解中定義的類(lèi)來(lái)檢查,需要的朋友可以參考下

1 @Contidional 介紹

Conditional 是由SpringFramework提供的一個(gè)注解,位于 org.springframework.context.annotation 包內(nèi),定義如下。

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

SpringBoot 模塊大量的使用@Conditional 注釋?zhuān)覀兛梢詫pring的@Conditional注解用于以下場(chǎng)景:

  • 可以作為類(lèi)級(jí)別的注解直接或者間接的與@Component相關(guān)聯(lián),包括@Configuration類(lèi);
  • 可以作為元注解,用于自動(dòng)編寫(xiě)構(gòu)造性注解;
  • 作為方法級(jí)別的注解,作用在任何@Bean方法上。

1.1 Condition 接口

我們需要一個(gè)類(lèi)實(shí)現(xiàn)Spring提供的Condition接口,它會(huì)匹配@Conditional所符合的方法,然后我們可以使用我們?cè)贎Conditional注解中定義的類(lèi)來(lái)檢查。

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

1.2 Spring @Conditional注解實(shí)例

作用在方法上

先來(lái)看一個(gè)簡(jiǎn)單一些的示例,我們假設(shè)有三個(gè)角色老師Teacher、學(xué)生Student和父母Parent,三種環(huán)境Linux、Windows和MacOSX,如果是Linux環(huán)境,就注冊(cè)Teacher,如果是Windows環(huán)境就注冊(cè)Parent,如果是Mac 環(huán)境就注冊(cè)Student。代碼示例如下:

首先創(chuàng)建Teacher和Student對(duì)象,沒(méi)有任何的屬性和方法,只是一個(gè)空類(lèi)

//如果當(dāng)前工程運(yùn)行在Windows系統(tǒng)下,就注冊(cè)Student
public class Student {}
//如果當(dāng)前工程運(yùn)行在Linux系統(tǒng)下,就注冊(cè)Teacher
public class Teacher {}
// 如果是Mac OSX 系統(tǒng),就注冊(cè)Parent
public class Parent {}

創(chuàng)建一個(gè)LinuxCondition和一個(gè)WindowsCondition,LinuxCondition能夠匹配Linux環(huán)境,WindowsCondition能夠匹配Windows環(huán)境,MacOSX 系統(tǒng)匹配mac環(huán)境。

 
public class LinuxCondition implements Condition {
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            // 獲取系統(tǒng)環(huán)境的屬性
          String systemName = context.getEnvironment().getProperty("os.name");
          if(systemName.contains("Linux")){
              return true;
          }
          return false;
    }
}
//自定義一個(gè)判斷條件
public class WindowsCondition implements Condition {
    /*
     * ConditionContext context: spring容器上下文環(huán)境
     * AnnotatedTypeMetadata metadata :@Conditional修飾類(lèi)型信息
     */
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
           String systemName = context.getEnvironment().getProperty("os.name");
           if(systemName.contains("Windows")){
               return true;
           }
        return false;
    }
}
public class OsxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String property = context.getEnvironment().getProperty("os.name");
        if(property.equals("Mac OS X")){
            return true;
        }
        return false;
    }
}

下面來(lái)新建匹配注冊(cè)環(huán)境,如果系統(tǒng)是Linux環(huán)境,就注冊(cè)Teacher,如果系統(tǒng)是Windows,就注冊(cè)Parent,如果是Mac 系統(tǒng),就注冊(cè)Student

 
@Configuration
public class AppConfig {
    @Conditional(OsxCondition.class)
    @Bean
    public Student student(){
        return new Student();
    }
    @Conditional(LinuxCondition.class)
    @Bean
    public Teacher teacher(){
        return new Teacher();
    }
    @Conditional(WindowsCondition.class)
    @Bean
    public Parent parent(){
        return new Parent();
    }
}

新建測(cè)試類(lèi)進(jìn)行測(cè)試

 
public class ConditionTest {
 
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        String[] names = context.getBeanDefinitionNames();
        for(String name : names){
            System.out.println("name = " + name);
        }
    }
}

由輸出可以看出,name = student 被輸出到控制臺(tái),也就是說(shuō),我當(dāng)前所用的系統(tǒng)環(huán)境是MacOSX環(huán)境,所以注冊(cè)的是OSXCondition,也就是student的bean。

手動(dòng)設(shè)置系統(tǒng)環(huán)境

也可以進(jìn)行手動(dòng)修改vm.options,把當(dāng)前的系統(tǒng)環(huán)境變?yōu)長(zhǎng)inux 或者Windows,以Idea為例:

img

在Edit Configurations中找到vm.options 選項(xiàng),把系統(tǒng)環(huán)境改為 Linux,如下:

img

然后重新啟動(dòng)測(cè)試,發(fā)現(xiàn)Teacher 被注入進(jìn)來(lái)了,修改當(dāng)前環(huán)境為Windows,觀察Parent也被注入進(jìn)來(lái)并輸出了。

作用在類(lèi)上

@Conditional 注解可以作用在類(lèi)上,表示此類(lèi)下面所有的bean滿足條件后都可以進(jìn)行注入,通常與@Configuration注解一起使用。

新建一個(gè)AppClassConfig,在類(lèi)上標(biāo)注@Conditional()注解,并配置相關(guān)bean,如下:

@Conditional(value = OsxCondition.class)

上文表示如果是OsxCondition.class 的話,就注冊(cè)student、teacher、parent

測(cè)試類(lèi)不用修改,直接用原測(cè)試類(lèi)進(jìn)行測(cè)試,發(fā)現(xiàn)student、 teacher、 parent 都被注冊(cè)進(jìn)來(lái)了

多個(gè)條件類(lèi)

因?yàn)锧Conditional注解的value 方法默認(rèn)傳遞一個(gè)數(shù)組,所以可以接受多個(gè)condition,為了測(cè)試如下情況,

新建一個(gè) TestCondition類(lèi),如下:

// 單純?yōu)榱藴y(cè)試
public class TestCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 返回false,表示不匹配
        return false;
    }
}

修改一下AppClassConfig

@Conditional(value = {OsxCondition.class,TestCondition.class})

也就是給@Conditional 多加了一個(gè)參數(shù) TestCondition.class

啟動(dòng)之前的測(cè)試類(lèi),發(fā)現(xiàn)上述的bean都沒(méi)有注入,也就是說(shuō),只有在滿足OsxCondition.class 和 TestCondition.class 都為true的情況下,才會(huì)注入對(duì)應(yīng)的bean,修改TestCondition.class的matches方法的返回值為true,重新觀察返回結(jié)果,發(fā)現(xiàn)上述bean都被注入了。

1.3 @Conditional 與@Profile 的對(duì)比

@Spring3.0 也有一些和@Conditional 相似的注解,它們是Spring SPEL 表達(dá)式和Spring Profiles 注解 Spring4.0的@Conditional 注解要比@Profile 注解更加高級(jí)。

@Profile 注解用來(lái)加載應(yīng)用程序的環(huán)境。@Profile注解僅限于根據(jù)預(yù)定義屬性編寫(xiě)條件檢查。 @Conditional注釋則沒(méi)有此限制。

Spring中的@Profile 和 @Conditional 注解用來(lái)檢查"If…then…else"的語(yǔ)義。然而,Spring4 @Conditional是@Profile 注解的更通用法。

  • Spring 3中的 @Profiles僅用于編寫(xiě)基于Environment變量的條件檢查。 配置文件可用于基于環(huán)境加載應(yīng)用程序配置。
  • Spring 4 @Conditional注解允許開(kāi)發(fā)人員為條件檢查定義用戶定義的策略。@Conditional可用于條件bean注冊(cè)。

2 Spring boot 擴(kuò)展

? SpringBoot的spring-boot-autoconfigure模塊也提供了Conditional系列的相關(guān)注解,這些注解能幫助開(kāi)發(fā)者根據(jù)一定的條件去裝載需要的Bean。

在這里插入圖片描述

2.1 @ConditionalOnClass和@ConditionalOnMissingClass注解

? 當(dāng)Spring加載的Bean被@ConditionOnClass注解標(biāo)記時(shí),類(lèi)加載器會(huì)先去先找到指定的Class, 如果沒(méi)有找到目標(biāo)Class,那么被ConditionOnClass注解標(biāo)記的類(lèi)不會(huì)被Spring裝載,相反ConditionalOnMissingBean是指如果沒(méi)有找到目標(biāo)Class, 那么就裝載該類(lèi)。

2.2 @ConditionalOnBean 和@ConditionalOnMissingBean注解

? 當(dāng)Spring加載的Bean被@ConditionalOnBean注解標(biāo)記時(shí),接下來(lái)會(huì)先找到指定的Bean,如果沒(méi)有找到目標(biāo)Bean,那么被@ConditionalOnBean標(biāo)記的類(lèi)不會(huì)被Spring裝載,相反ConditionalOnMissingBean是指如果沒(méi)有Class, 那么就裝載該Bean。

? 看一個(gè)例子, Dubbo與Springboot做自動(dòng)裝配時(shí),先尋找BASE_PACKAGES_BEAN_NAME這個(gè)Bean, 如果Bean 不存在,那么serviceAnnotationBeanProcessor這個(gè)Bean不會(huì)被Spring 裝載.

@ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true)
@Configuration
@AutoConfigureAfter(DubboRelaxedBindingAutoConfiguration.class)
@EnableConfigurationProperties(DubboConfigurationProperties.class)
@EnableDubboConfig
public class DubboAutoConfiguration {
    /**
     * Creates {@link ServiceAnnotationPostProcessor} Bean
     * dubbo.scan.base-packages
     * @param packagesToScan the packages to scan
     * @return {@link ServiceAnnotationPostProcessor}
     */
    @ConditionalOnProperty(prefix = DUBBO_SCAN_PREFIX, name = BASE_PACKAGES_PROPERTY_NAME)
    // 先找BASE_PACKAGES_BEAN_NAME 這個(gè)bean, 如果沒(méi)有這個(gè)bean, 那么serviceAnnotationBeanProcessor不會(huì)被Spring裝載。
    @ConditionalOnBean(name = BASE_PACKAGES_BEAN_NAME)
    @Bean
    public ServiceAnnotationPostProcessor serviceAnnotationBeanProcessor(@Qualifier(BASE_PACKAGES_BEAN_NAME)
                                                                       Set<String> packagesToScan) {
        return new ServiceAnnotationPostProcessor(packagesToScan);
    }
}

? 使用@ConditionalOnMissingBean注解定義BASE_PACKAGES_BEAN_NAME這個(gè)Bean

/**
 * Dubbo Relaxed Binding Auto-{@link Configuration} for Spring Boot 2.0
 *
 * @see DubboRelaxedBindingAutoConfiguration
 * @since 2.7.0
 */
@Configuration
@ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true)
@ConditionalOnClass(name = "org.springframework.boot.context.properties.bind.Binder")
@AutoConfigureBefore(DubboRelaxedBindingAutoConfiguration.class)
public class DubboRelaxedBinding2AutoConfiguration {
    public PropertyResolver dubboScanBasePackagesPropertyResolver(ConfigurableEnvironment environment) {
        ConfigurableEnvironment propertyResolver = new AbstractEnvironment() {
            @Override
            protected void customizePropertySources(MutablePropertySources propertySources) {
                Map<String, Object> dubboScanProperties = getSubProperties(environment.getPropertySources(), DUBBO_SCAN_PREFIX);
                propertySources.addLast(new MapPropertySource("dubboScanProperties", dubboScanProperties));
            }
        };
        ConfigurationPropertySources.attach(propertyResolver);
        return propertyResolver;
    }
    /**
     * The bean is used to scan the packages of Dubbo Service classes
     * 如果沒(méi)有就創(chuàng)建
     * @param environment {@link Environment} instance
     * @return non-null {@link Set}
     * @since 2.7.8
     */
    @ConditionalOnMissingBean(name = BASE_PACKAGES_BEAN_NAME)
    @Bean(name = BASE_PACKAGES_BEAN_NAME)
    public Set<String> dubboBasePackages(ConfigurableEnvironment environment) {
        PropertyResolver propertyResolver = dubboScanBasePackagesPropertyResolver(environment);
        return propertyResolver.getProperty(BASE_PACKAGES_PROPERTY_NAME, Set.class, emptySet());
    }
    @ConditionalOnMissingBean(name = RELAXED_DUBBO_CONFIG_BINDER_BEAN_NAME, value = ConfigurationBeanBinder.class)
    @Bean(RELAXED_DUBBO_CONFIG_BINDER_BEAN_NAME)
    @Scope(scopeName = SCOPE_PROTOTYPE)
    public ConfigurationBeanBinder relaxedDubboConfigBinder() {
        return new BinderDubboConfigBinder();
    }
}

2.3 @ConditionalOnProperty注解

? 該注解的作用是解析application.yml/application.properties 里的配置生成條件來(lái)生效,也是與@Configuration注解一起使用。

屬性功能
prefix讀取配置里的前綴值為prefix的屬性, 如果沒(méi)有返回false
name讀取屬性配置里的Key值,如果配置了prefix,那么需要先拼接prefix然后匹配havingValue值
havingValue匹配屬性里的值
matchIfMissing當(dāng)未找到對(duì)應(yīng)的配置時(shí)是否匹配,默認(rèn)為false, 如果為true,沒(méi)有找到配置,那么也匹配。

? 使用場(chǎng)景,例如在指定數(shù)據(jù)源時(shí),指定datasource的type。

例如包含如下配置使用Hikari數(shù)據(jù)源。

spring.datasource.type=com.zaxxer.hikari.HikariDataSource

img

? 在使用時(shí),一般設(shè)置matchIfMissing=false, 這樣條件沒(méi)有匹配上的話會(huì)Spring在掃描bean時(shí)會(huì)自動(dòng)跳過(guò)該配置類(lèi)。

? 也可以設(shè)定matchIfMissing=true,這種場(chǎng)景例如緩存,我們可以這樣配置默認(rèn)是開(kāi)啟緩存的。

@ConditionalOnProperty(name={cache.effect},marchIfMissing=true)
public class CacheAutoConfiguration{
   // ...
}

? 如果在application.properties里配置cache.effect=false, 那么該配置類(lèi)就會(huì)跳過(guò),這樣配置就能使緩存不生效。

到此這篇關(guān)于Spring框架中的@Conditional系列注解詳解的文章就介紹到這了,更多相關(guān)Spring的@Conditional注解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MyBatis 多表查詢?nèi)N最常見(jiàn)的寫(xiě)法

    MyBatis 多表查詢?nèi)N最常見(jiàn)的寫(xiě)法

    這篇文章主要介紹了MyBatis 多表查詢?nèi)N最常見(jiàn)的寫(xiě)法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2025-04-04
  • Java中HttpServletResponse響應(yīng)中文出現(xiàn)亂碼問(wèn)題

    Java中HttpServletResponse響應(yīng)中文出現(xiàn)亂碼問(wèn)題

    這篇文章主要介紹了Java中HttpServletResponse響應(yīng)中文出現(xiàn)亂碼問(wèn)題的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-06-06
  • SpringBootWeb?入門(mén)了解?Swagger?的具體使用

    SpringBootWeb?入門(mén)了解?Swagger?的具體使用

    這篇文章主要介紹了SpringBootWeb?入門(mén)了解?Swagger?的具體使用,Swagger?框架可以根據(jù)已經(jīng)實(shí)現(xiàn)的方法或者類(lèi),通過(guò)頁(yè)面的方式直觀清晰的查看或者進(jìn)行測(cè)試該方法,需要的朋友可以參考下
    2024-08-08
  • MyBatis Generator生成代碼及使用方式詳解

    MyBatis Generator生成代碼及使用方式詳解

    這篇文章主要介紹了MyBatis Generator生成代碼及使用方式的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-09-09
  • MybatisPlus修改時(shí)空字段無(wú)法修改的解決方案

    MybatisPlus修改時(shí)空字段無(wú)法修改的解決方案

    這篇文章主要介紹了MybatisPlus修改時(shí)空字段無(wú)法修改的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Spring整合Quartz實(shí)現(xiàn)定時(shí)任務(wù)調(diào)度的方法

    Spring整合Quartz實(shí)現(xiàn)定時(shí)任務(wù)調(diào)度的方法

    下面小編就為大家?guī)?lái)一篇Spring整合Quartz實(shí)現(xiàn)定時(shí)任務(wù)調(diào)度的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-11-11
  • 解決springboot 無(wú)法配置多個(gè)靜態(tài)路徑的問(wèn)題

    解決springboot 無(wú)法配置多個(gè)靜態(tài)路徑的問(wèn)題

    這篇文章主要介紹了解決springboot 無(wú)法配置多個(gè)靜態(tài)路徑的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java構(gòu)造器使用方法及注意事項(xiàng)

    Java構(gòu)造器使用方法及注意事項(xiàng)

    這篇文章主要介紹了Java構(gòu)造器使用方法及注意事項(xiàng)的相關(guān)資料,這里舉例說(shuō)明如何使用構(gòu)造器及需要注意的地方,需要的朋友可以參考下
    2017-07-07
  • shiro之記住登錄信息

    shiro之記住登錄信息

    Shiro提供了記住我(RememberMe)的功能,當(dāng)關(guān)閉瀏覽器時(shí)下次再次打開(kāi)還能記住你的信息,下面小編給大家分享shiro之記住登錄信息的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2017-09-09
  • java比較兩個(gè)json文件的差異及說(shuō)明

    java比較兩個(gè)json文件的差異及說(shuō)明

    這篇文章主要介紹了java比較兩個(gè)json文件的差異及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10

最新評(píng)論