關(guān)于@SpringBootApplication與@SpringBootTest的區(qū)別及用法
@SpringBootApplication與@SpringBootTest區(qū)別用法
1 @SpringBootApplication 注解的應(yīng)用
一般情況我們使用 @SpringBootApplication 注解來啟動(dòng) SpringBoot 項(xiàng)目
它其實(shí)只相當(dāng)于 @Configuration、@EnableAutoConfiguration、@ComponentScan(包含了兩個(gè)filter)
@SpringBootApplication public class FrameworkUnitRealTestApp { ? ? public static void main(String[] args) { ? ? ? ? SpringApplication.run(FrameworkUnitRealTestApp.class, args); ? ? } }
2 @SpringBootTest 注解的應(yīng)用
一般情況我們使用 @SpringBootTest 和 @RunWith(SpringRunner.class) 注解來啟動(dòng) SpringBoot 測(cè)試項(xiàng)目
@RunWith(SpringRunner.class)? @SpringBootTest public class FrameworkUnitRealTestApp { ? ? @Test ? ? public void test() {} }
3 @SpringBootApplication 和 @SpringBootTest 的區(qū)別
這兩個(gè)注解的區(qū)別的核心在于兩個(gè)注解:@EnableAutoConfiguration、@ComponentScan(包含了兩個(gè)filter)
@EnableAutoConfiguration 啟動(dòng)了所有的自動(dòng)配置類
@ComponentScan(包含了兩個(gè)filter):在掃描階段過濾掉 @TestComponent 等專屬于測(cè)試的類和過濾掉被 @Configuration 注解的自動(dòng)配置類(使得自動(dòng)配置類不會(huì)在掃描階段就被注冊(cè) beanDefinition,因?yàn)?自動(dòng)配置類的優(yōu)先級(jí)應(yīng)該是最低的)
可以看出 @SpringBootTest 并沒有啟用任何自動(dòng)配置類,所以就不需要加 AutoConfigurationExcludeFilter 了
springboot 通過引入 @Test** 注解來在 測(cè)試環(huán)境下 引入不同的自動(dòng)配置類!
4 @ComponentScan(包含了兩個(gè)filter) 解析
詳細(xì)的代碼如下:添加了 TypeExcludeFilter 和 AutoConfigurationExcludeFilter 兩個(gè) excludeFilter
作用:掃描包的時(shí)候過濾掉被這兩個(gè) Filter 匹配的類!
@ComponentScan(excludeFilters = { ?? ??? ?@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), ?? ??? ?@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
4.1 TypeExcludeFilter 解析
主要移除測(cè)試相關(guān)的類
public class TypeExcludeFilter implements TypeFilter, BeanFactoryAware { ? ?@Override ? ?public boolean match(MetadataReader metadataReader, ? ? ? ? ?MetadataReaderFactory metadataReaderFactory) throws IOException { ? ? ? if (this.beanFactory instanceof ListableBeanFactory ? ? ? ? ? ? && getClass() == TypeExcludeFilter.class) { ? ? ? ? ?Collection<TypeExcludeFilter> delegates = ((ListableBeanFactory) this.beanFactory) ? ? ? ? ? ? ? ?.getBeansOfType(TypeExcludeFilter.class).values(); ? ? ? ? ?for (TypeExcludeFilter delegate : delegates) { ? ? ? ? ? ? if (delegate.match(metadataReader, metadataReaderFactory)) { ? ? ? ? ? ? ? ?return true; ? ? ? ? ? ? } ? ? ? ? ?} ? ? ? } ? ? ? return false; ? ?} } //delegate.match 走這個(gè)類的 match 方法 class TestTypeExcludeFilter extends TypeExcludeFilter { ?? ?private static final String[] CLASS_ANNOTATIONS = { "org.junit.runner.RunWith", ?? ??? ??? ?"org.junit.jupiter.api.extension.ExtendWith" }; ?? ?private static final String[] METHOD_ANNOTATIONS = { "org.junit.Test", ?? ??? ??? ?"org.junit.platform.commons.annotation.Testable" }; ?? ?@Override ?? ?public boolean match(MetadataReader metadataReader, ?? ??? ??? ?MetadataReaderFactory metadataReaderFactory) throws IOException { ? ? ? ? //是否被 @TestComponent 及其父注解注釋 ?? ??? ?if (isTestConfiguration(metadataReader)) {return true;} ? ? ? ? //類上或類中方法上有沒有 CLASS_ANNOTATIONS、METHOD_ANNOTATIONS 中的注解 ?? ??? ?if (isTestClass(metadataReader)) {return true;} ?? ??? ?String enclosing = metadataReader.getClassMetadata().getEnclosingClassName(); ?? ??? ?if (enclosing != null) { ? ? ? ? ? ? //遞歸內(nèi)部類、父類 ? ? ? ? ? ? if (match(metadataReaderFactory.getMetadataReader(enclosing), ? ? ? ? ? ? ? ? ? ? ? metadataReaderFactory)) { ? ? ? ? ? ? ? ? return true; ? ? ? ? ? ? } ?? ??? ?} ?? ??? ?return false; ?? ?} }
4.2 AutoConfigurationExcludeFilter 解析
主要移除被 @Configuration 修飾的 自動(dòng)配置類
public class AutoConfigurationExcludeFilter implements TypeFilter, BeanClassLoaderAware { ?? ?@Override ?? ?public boolean match(MetadataReader metadataReader, ?? ??? ??? ?MetadataReaderFactory metadataReaderFactory) throws IOException { ? ? ? ? //如果被 @Configuration 注解,并且是 自動(dòng)配置類就返回 true,即匹配成功? ? ? ? ? //注:被 @Component 等注解并不匹配 ?? ??? ?return isConfiguration(metadataReader) && isAutoConfiguration(metadataReader); ?? ?} }
5 @EnableAutoConfiguration 注解解析
作用:啟用自動(dòng)配置類
@AutoConfigurationPackage //啟用 AutoConfigurationImportSelector 配置類:掃描得到所有自動(dòng)配置類 @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { ? ?String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; ? ?//定義不啟用的 自動(dòng)配置類 ? ?Class<?>[] exclude() default {}; ? ?//同上 ? ?String[] excludeName() default {}; } //這個(gè)注解主要是向容器中注冊(cè) AutoConfigurationPackages.Registrar 類用來存儲(chǔ)自動(dòng)配置包 @Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage {} //關(guān)鍵:這個(gè)類繼承了 DeferredImportSelector 接口,所以是到最后才解析的??! public class AutoConfigurationImportSelector implements DeferredImportSelector{ ? ? @Override ? ? public String[] selectImports(AnnotationMetadata annotationMetadata) { ? ? ? ? if (!isEnabled(annotationMetadata)) { ? ? ? ? ? ? return NO_IMPORTS; ? ? ? ? } ? ? ? ? AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader ? ? ? ? ? ? .loadMetadata(this.beanClassLoader); ? ? ? ? AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry( ? ? ? ? ? ? autoConfigurationMetadata, annotationMetadata); ? ? ? ? return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); ? ? } }
6 @…Test 注解
Spring Boot 中文文檔 對(duì)每個(gè) @…Test 注解導(dǎo)入的自動(dòng)配置類做了詳細(xì)的說明
SpringBootTest對(duì)比SpringBootApplication
SpringBootTest 是測(cè)試使用類的注解,標(biāo)志這個(gè)類是測(cè)試用例。
具體看下源碼分析
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @BootstrapWith(SpringBootTestContextBootstrapper.class) @ExtendWith({SpringExtension.class}) public @interface SpringBootTest {
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} ) public @interface SpringBootApplication {
對(duì)比顯示都是復(fù)合注解,并且前四個(gè)注解是一樣的,后面區(qū)分BootstrapWith和ExtendWith這兩個(gè)是測(cè)試中包含的
BootstrapWith這個(gè)注解中有一個(gè)參數(shù)為SpringBootTestContextBootstrapper
具體可以看下里面是什么
這里面申明了一些程序運(yùn)行所在包的路徑,在去查看繼承的頂級(jí)類可以追溯到TestContextBootstrapper 這個(gè)接口 :
從里面的方法可以看到是在運(yùn)行的時(shí)候設(shè)置上下文 以及如何獲取上下文,來提供測(cè)試啟動(dòng)的必須值。
接下來看下 ExtendWith 這個(gè)注解類
這個(gè)主要看里面的SpringExtension這個(gè)參數(shù)
可以看出這個(gè)實(shí)現(xiàn)了很多接口,來處理測(cè)試需要的各種通知處理,以及在測(cè)試接口時(shí)可以提前處理請(qǐng)求參數(shù)。
SpringBootApplication中的復(fù)合注解則是掃描一些包和配置。雖然測(cè)試也是項(xiàng)目啟動(dòng)的一種,可以看到里面實(shí)現(xiàn)還是有些區(qū)別的。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java實(shí)現(xiàn)簡單的猜數(shù)字小游戲
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡單猜數(shù)字小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-03-03Spring?Cloud?Gateway中netty線程池優(yōu)化示例詳解
這篇文章主要介紹了Spring?Cloud?Gateway中netty線程池優(yōu)化示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07在SpringBoot項(xiàng)目中實(shí)現(xiàn)讀寫分離的流程步驟
SpringBoot作為一種快速開發(fā)框架,廣泛應(yīng)用于Java項(xiàng)目中,在一些大型應(yīng)用中,數(shù)據(jù)庫的讀寫分離是提升性能和擴(kuò)展性的一種重要手段,本文將介紹如何在SpringBoot項(xiàng)目中優(yōu)雅地實(shí)現(xiàn)讀寫分離,并通過適當(dāng)?shù)拇a插入,詳細(xì)展開實(shí)現(xiàn)步驟,同時(shí)進(jìn)行拓展和分析2023-11-11Java實(shí)現(xiàn)經(jīng)典游戲飛機(jī)大戰(zhàn)-I的示例代碼
《飛機(jī)大戰(zhàn)-I》是一款融合了街機(jī)、競(jìng)技等多種元素的經(jīng)典射擊手游。本文將利用java語言實(shí)現(xiàn)這游戲,文中采用了swing技術(shù)進(jìn)行了界面化處理,感興趣的可以了解一下2022-02-02Maven的pom.xml文件結(jié)構(gòu)中的build
本文主要介紹了Maven的pom.xml文件結(jié)構(gòu)中的build,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07FastJson時(shí)間格式化問題避坑經(jīng)驗(yàn)分享
這篇文章主要為大家介紹了FastJson時(shí)間格式化問題避坑經(jīng)驗(yàn)分享,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08