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

詳解SpringBoot中@ConditionalOnClass注解的使用

 更新時間:2022年08月03日 08:28:40   作者:良工說技術  
這篇文章主要和大家詳細介紹一下springboot中@ConditionalOnClass注解的用法,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下

今天給大家?guī)淼氖莝pringboot中的@ConditionalOnClass注解的用法。上次的@ConditionalOnBean注解還記得嗎?

一、@ConditionalOnClass注解初始

看下@CodidtionalOnClass注解的定義,

需要注意的有兩點,

  • 該注解可以用在類及方法上;類指的是標有@Configuration的類,方法是標有@Bean的方法;
  • 該注解使用了@Conditional注解標記;這是重點

看到這里,有小伙伴會疑惑,講了那么多@Conditional注解的作用是什么,不急,作用馬上來。

@ConditionalOnClass注解的作用是當項目中存在某個類時才會使標有該注解的類或方法生效;

這句話有點拗口,通俗的講,@ConditionalOnClass標識在@Configuration類上,只有存在@ConditionalOnClass中value/name配置的類該Configuration類才會生效;@ConditionalOnClass標識在@Bean方法上,只有只有存在@ConditionalOnClass中value/name配置的類方法才會生效??淳唧w的實例更容易理解些

二、@ConditionalOnClass注解用法

從上面@ConditionalOnClass注解的定義中我們知道該注解可以配置兩個屬性,分別是value和name,其中value和name都是數組,只不過內容不一樣,

value是Class的數組,name是全限類名的字符串。

1、使用value屬性

開始,我一直使用value屬性進行配置,但是總是報錯,比如我配置

@Configuration
@ConditionalOnClass(value = {Client.class})
public class MyAutoConfig {
    public MyAutoConfig(){
        System.out.println("constructor MyAutoConfig");
    }
}

該Client是下面的類,

org.springframework.boot.autoconfigure.data.elasticsearch.Client

它是ES中的一個類,我本身配置的含義是只有在Client存在的時候MyAutoConfig才會生效,但是總是不成功。你知道為什么不成功嗎?

這是因為我沒有引ES的依賴,導致在我的classpath中沒有這個類,按照@ConditionalOnClass的理解,應該是不存在則不會生效,但是由于沒有這個類,導致的問題是:無法編譯,提示下面的錯誤

java: 找不到符號
  符號: 類 Client

這是可以理解的,因為沒有這個類,而我要引用這個類肯定是引用不到的,所以編譯是失敗的,也就程序跑不起來。那么存在一個問題,@ConditionalOnClass注解的value屬性要在什么情況下使用?

這里有一個mybatisplus的配置類,

其配置類上標識了@ConditionalOnClass注解,該注解中配置了value屬性,且配置了SqlSessionFactory和SqlSessionFactoryBean兩個類,

MyBatisPlusAutoConfiguration是在mybatis-plus-boot-starter的jar包下

SqlSessionFactory是在mybatis的jar包下

SqlSessionFactoryBean是在mybaits-spring的jar包下

這三個類分屬于不同的jar包,如果我在一個項目中引入了mybatis-plus-boot-starter的jar包,沒有引入mybatis的jar包那么MybatisPlusAutoConfiguration不會生效,也就是只有mybatis和mybatis-spring的jar包都引入了,MybatisPlusAutoConfiguration才會生效,才會被納入spring容器的管理。

需要注意一點:為了防止少引包,在mybatis-plus-boot-starter中會依賴mybatis和mybatis-spring,這也是starter的好處,不會少引包,需要哪些依賴它都引好了。

那么再回到問題的開始,為什么,我配置了一個不存在的類就沒成功,那是因為java的源文件需要編譯,在編譯時會檢查類是否存在,不存在肯定是編譯不通過的;而如果引用的是jar包中的文件引用另外一個jar的,則是因為jar包經過了編譯,已經打包成功了,故不存在問題。

通過value屬性需要結合jar包的方式,這里就不演示了,感興趣的小伙伴可以自己嘗試。通過name屬性來指定。

2、使用name屬性

@ConditionalOnClass注解還有name屬性,name屬性指定的是全限類名,也就是包含包名+類名。看下我的配置,

@Configuration
@ConditionalOnClass(name = {"com.my.template.config.ClassA"})
public class MyAutoConfig {
    public MyAutoConfig(){
        System.out.println("constructor MyAutoConfig");
    }
}

這里配置了“com.my.template.config.ClassA”,ClassA是我的一個存在的類,

下面啟動,看下在啟動日志中是否有“constructor MyConfig”打印,

constructor MyAutoConfig
constructor MyAutoConfig2
constructor classA
2022-07-30 17:18:54.113 

看到了,日志說明name配置是生效的,也就是存在ClassA則MyAutoConfig會注冊到spring的容器中。作為對比,下面配置一個不存在的類ClassD,

@Configuration
@ConditionalOnClass(name = {"com.my.template.config.ClassD"})
public class MyAutoConfig {
    public MyAutoConfig(){
        System.out.println("constructor MyAutoConfig");
    }
}

看下啟動日志

constructor MyAutoConfig2
constructor classA
2022-07-30 21:43:30.550  INFO 13116 --- [  

從上面的日志可以看到,沒有打印出來想要的日志,說明MyAutoConfig沒有注冊到spring的容器中。

我們知道name屬性是一個數組,上面僅僅配置了一個類,如果配置多個會是什么樣子,感興趣的可以自己嘗試,這里這直接給出答案,只有name屬性中配置的全部滿足相應的配置類才會生效。

不知道,你是否對@ConditionalOnClass是怎么實現的感興趣嗎,繼續(xù)往下看,大揭秘了。

三、@ConditionalOnClass是怎么實現的

要理解@ConditionalOnClass是怎么實現的還是要回到該注解的定義上,前邊提到該注解被

@Conditional(OnClassCondition.class)

注解標識,@Conditional注解的含有是要滿足條件才會生效,該注解后邊再看。今天的主角是OnClassCondition類,看下其繼承關系

重點關注XXCondition即可,可以看到最終實現了Condition接口,@Conditional注解的本質就是考查是否滿足Codition接口的matches()方法,所以這看SpringBootCondition中matches方法的實現,

@Override
	public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //獲得該注解標準的類或方法
		String classOrMethodName = getClassOrMethodName(metadata);
		try {
            //模板方法,該實現在OnClassCodition類中
			ConditionOutcome outcome = getMatchOutcome(context, metadata);
			logOutcome(classOrMethodName, outcome);
			recordEvaluation(context, classOrMethodName, outcome);
            //返回是否符合條件
			return outcome.isMatch();
		}
		catch (NoClassDefFoundError ex) {
			throw new IllegalStateException("Could not evaluate condition on " + classOrMethodName + " due to "
					+ ex.getMessage() + " not found. Make sure your own configuration does not rely on "
					+ "that class. This can also happen if you are "
					+ "@ComponentScanning a springframework package (e.g. if you "
					+ "put a @ComponentScan in the default package by mistake)", ex);
		}
		catch (RuntimeException ex) {
			throw new IllegalStateException("Error processing condition on " + getName(metadata), ex);
		}
	}

getMatchOutCome()方法使用了模板方法,實現在OnClassCondition類中,這是最要的方法,

@Override
	public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
		ClassLoader classLoader = context.getClassLoader();
		ConditionMessage matchMessage = ConditionMessage.empty();
         //獲得@ConditionalOnClass注解中配置的value和name屬性的值
		List<String> onClasses = getCandidates(metadata, ConditionalOnClass.class);
		if (onClasses != null) {
            //判斷@ConditionOnClass注解配置的類是否都可以加載到,如有加載不到的則放到missing中
			List<String> missing = filter(onClasses, ClassNameFilter.MISSING, classLoader);
			if (!missing.isEmpty()) {
                //有加載不到的,則返回ConditionOutcome對下,其中屬性match為false
				return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
						.didNotFind("required class", "required classes").items(Style.QUOTE, missing));
			}
			matchMessage = matchMessage.andCondition(ConditionalOnClass.class)
					.found("required class", "required classes")
					.items(Style.QUOTE, filter(onClasses, ClassNameFilter.PRESENT, classLoader));
		}
        //@ConditionalOnMissingClass的處理邏輯
		List<String> onMissingClasses = getCandidates(metadata, ConditionalOnMissingClass.class);
		if (onMissingClasses != null) {
			List<String> present = filter(onMissingClasses, ClassNameFilter.PRESENT, classLoader);
			if (!present.isEmpty()) {
				return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnMissingClass.class)
						.found("unwanted class", "unwanted classes").items(Style.QUOTE, present));
			}
			matchMessage = matchMessage.andCondition(ConditionalOnMissingClass.class)
					.didNotFind("unwanted class", "unwanted classes")
					.items(Style.QUOTE, filter(onMissingClasses, ClassNameFilter.MISSING, classLoader));
		}
        //返回ConditionOutCome對下,其match屬性為true
		return ConditionOutcome.match(matchMessage);
	}

上面的代碼已經給出了注釋,對應@ConditionalOnClass注解的處理就是解析器配置的value和name屬性,判斷配置的類是否加載到,如有未加載到的則直接返回屬性match=false的ConditionOutcome對象,那么是如何判斷是否加載到的,是通過FilteringSpringBootCondition中的filter方法,

protected final List<String> filter(Collection<String> classNames, ClassNameFilter classNameFilter,
			ClassLoader classLoader) {
		if (CollectionUtils.isEmpty(classNames)) {
			return Collections.emptyList();
		}
		List<String> matches = new ArrayList<>(classNames.size());
		for (String candidate : classNames) {
            //循環(huán)調用matches方法
			if (classNameFilter.matches(candidate, classLoader)) {
				matches.add(candidate);
			}
		}
		return matches;
	}

對于@CoditionalOnClass的處理該方法傳入的參數為

List<String> missing = filter(onClasses, ClassNameFilter.MISSING, classLoader);

那么也就是調用ClassNameFilter.MISSING的matches方法,其方法如下

可以看到調用的是!isPresent方法,看下該方法的實現,

static boolean isPresent(String className, ClassLoader classLoader) {
            if (classLoader == null) {
                classLoader = ClassUtils.getDefaultClassLoader();
            }

            try {
                //具體實現邏輯
                FilteringSpringBootCondition.resolve(className, classLoader);
                return true;
            } catch (Throwable var3) {
                return false;
            }
        }

具體的實現在resolve方法中,且該方法被try catch包住了,如果加載不到,直接返回false。

protected static Class<?> resolve(String className, ClassLoader classLoader) throws ClassNotFoundException {
        return classLoader != null ? Class.forName(className, false, classLoader) : Class.forName(className);
    }

看到這里,大家明白了,@ConditionalOnClass注解中判斷配置的類是否存在使用的方法是Class.forName,類加載。

四、總結

本文主要認識了@ConditionalOnClass注解,分析了其注解的原理,如何判斷配置的類是否存在。

  • @ConditionalOnClass注解有兩個屬性,分別是value和name,注意其配置方式;
  • @ConditionalOnClass注解判斷配置的類是否存在的方式是通過Class.forName的方式;

以上就是詳解SpringBoot中@ConditionalOnClass注解的使用的詳細內容,更多關于SpringBoot @ConditionalOnClass注解的資料請關注腳本之家其它相關文章!

相關文章

  • jvm支持最大線程數簡單測試

    jvm支持最大線程數簡單測試

    這篇文章主要介紹了jvm支持最大線程數簡單測試,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11
  • Netty與Spring Boot的整合實現

    Netty與Spring Boot的整合實現

    這篇文章主要介紹了Netty與Spring Boot的整合的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-08-08
  • Java fastjson2 解析JSON用法詳解

    Java fastjson2 解析JSON用法詳解

    Fastjson2是Fastjson的升級版,提供了更好的性能和擴展性,它支持多種方式解析JSON數據,包括將JSON字符串轉換為Java對象、嵌套的JSON對象和數組,以及轉換成Map或List,本文介紹Java fastjson2 解析JSON用法,感興趣的朋友一起看看吧
    2025-02-02
  • Java將文件壓縮成zip并下載

    Java將文件壓縮成zip并下載

    這篇文章主要為大家詳細介紹了Java如何將文件壓縮成zip和下載,并處理base64和url,文中的示例代碼講解詳細,感興趣的小伙伴可以參考一下
    2025-04-04
  • 詳解SpringBoot禁用Swagger的三種方式

    詳解SpringBoot禁用Swagger的三種方式

    在生產環(huán)境下,我們需要關閉swagger配置,避免暴露接口的這種危險行為。本文就詳細的介紹了3種情況,感興趣的可以了解一下
    2021-11-11
  • java開發(fā)技巧代碼寫的快且bug少的原因分析

    java開發(fā)技巧代碼寫的快且bug少的原因分析

    這篇文章主要為大家介紹了java開發(fā)中代碼寫的快且bug少的原因分析及技巧詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • SpringMVC全局異常處理小結

    SpringMVC全局異常處理小結

    在開發(fā)中,不管是dao層、service層還是controller層,都有可能拋出異常,在springmvc中,能將所有類型的異常處理從各處理過程解耦出來,既保證了相關處理過程的功能較單一,也實現了異常信息的統(tǒng)一處理和維護,本文介紹SpringMVC全局異常處理,感興趣的朋友一起看看吧
    2024-03-03
  • 批量上傳Jar包到Maven私服的工具的方法

    批量上傳Jar包到Maven私服的工具的方法

    這篇文章主要介紹了批量上傳Jar包到Maven私服的工具的方法,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • Springboot實現添加本地模塊依賴方式

    Springboot實現添加本地模塊依賴方式

    這篇文章主要介紹了Springboot實現添加本地模塊依賴方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • java實現簡單的搜索引擎

    java實現簡單的搜索引擎

    這篇文章主要為大家詳細介紹了java實現簡單的搜索引擎的相關資料,需要的朋友可以參考下
    2016-02-02

最新評論

东山县| 府谷县| 逊克县| 宝清县| 乐安县| 滕州市| 鸡泽县| 瑞丽市| 邵武市| 个旧市| 东乌| 淮阳县| 西青区| 奉节县| 安义县| 乌拉特中旗| 石首市| 揭阳市| 咸阳市| 藁城市| SHOW| 芦溪县| 平远县| 红安县| 余庆县| 英超| 安西县| 介休市| 龙岩市| 福建省| 安新县| 板桥市| 饶河县| 大英县| 永仁县| 中西区| 桦甸市| 恩平市| 上饶县| 秦安县| 三台县|