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

springboot自動裝配之@ComponentScan使用方式

 更新時間:2025年01月23日 15:07:16   作者:qq_39093474  
@componentScan注解用于掃描指定路徑下的組件,并自動將它們注冊為Spring?Bean,該注解支持多種過濾規(guī)則,可以自定義掃描過濾規(guī)則,Spring?Boot通過ConfigurationClassPostProcessor處理@ComponentScan注解,并在啟動時創(chuàng)建和注冊BeanDefinition對象

1.@ComponentScan注解作用

@ComponentScan用于類或接口上主要是指定掃描路徑,spring會把指定路徑下帶有指定注解的類自動裝配到bean容器里。

會被自動裝配的注解包括@Controller、@Service@Component、@Repository等等。

ComponentScan注解相對應的XML配置就是<context:component-scan/>, 根據(jù)指定的配置自動掃描package,將符合條件的組件加入到IOC容器中;

XML的配置方式如下:

	<context:component-scan
		base-package="com.example.test" use-default-filters="false">
		<context:exclude-filter type="custom"
		expression="com.example.test.filter.MtyTypeFilter" />
	</context:component-scan>

2. @ComponentScan注解屬性

@ComponentScan有如下常用屬性:

  • basePackagesvalue:指定要掃描的路徑(package),如果為空則以@ComponentScan注解的類所在的包為基本的掃描路徑。
  • basePackageClasses:指定具體掃描的類。
  • includeFilters:指定滿足Filter條件的類。
  • excludeFilters:指定排除Filter條件的類。
  • useDefaultFilters=true/false:指定是否需要使用Spring默認的掃描規(guī)則:被@Component, @Repository, @Service, @Controller或者已經(jīng)聲明過@Component自定義注解標記的組件;

在過濾規(guī)則Filter中:

FilterType:指定過濾規(guī)則,支持的過濾規(guī)則有:

  • ANNOTATION:按照注解規(guī)則,過濾被指定注解標記的類(默認);
  • ASSIGNABLE_TYPE:按照給定的類型;
  • ASPECTJ:按照ASPECTJ表達式;
  • REGEX:按照正則表達式;
  • CUSTOM:自定義規(guī)則,自定義的Filter需要實現(xiàn)TypeFilter接口;

value和classes:指定在該規(guī)則下過濾的表達式;

@ComponentScan的常見的配置如下:

@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)

3. @ComponentScan過濾規(guī)則說明

規(guī)則表達式說明:

  • 1.掃描指定類文件
@ComponentScan(basePackageClasses = Person.class)
  • 2.掃描指定包,使用默認掃描規(guī)則,即被@Component, @Repository, @Service, @Controller或者已經(jīng)聲明過@Component自定義注解標記的組件;
@ComponentScan(value = "com.example")
  • 3.掃描指定包,加載被@Component注解標記的組件和默認規(guī)則的掃描(因為useDefaultFilters默認為true)
@ComponentScan(value = "com.example", includeFilters = { @Filter(type = FilterType.ANNOTATION, value = Component.class) })
  • 4.掃描指定包,只加載Person類型的組件
@ComponentScan(value = "com.example", includeFilters = { @Filter(type = FilterType.ASSIGNABLE_TYPE, value = Person.class) }, useDefaultFilters = false)
  • 5.掃描指定包,過濾掉被@Component標記的組件
@ComponentScan(value = "com.example", excludeFilters = { @Filter(type = FilterType.ANNOTATION, value = Component.class) })
  • 6.掃描指定包,自定義過濾規(guī)則
@ComponentScan(value = "com.example", includeFilters = { @Filter(type = FilterType.CUSTOM, value = MtyTypeFilter.class) }, useDefaultFilters = true)

4. 自定義掃描過濾規(guī)則

用戶自定義掃描過濾規(guī)則,需要實現(xiàn)org.springframework.core.type.filter.TypeFilter接口。

//1.自定義類實現(xiàn)TypeFilter接口并重寫match()方法
public class MtyTypeFilter implements TypeFilter {
    /**
     *
     * @param metadataReader:讀取到當前正在掃描的類的信息
     * @param metadataReaderFactory:可以獲取到其他任何類的信息
     * @return
     * @throws IOException
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        System.out.println("========MtyTypeFilter===========");
        //獲取當前類的注解的信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        System.out.println("annotationMetadata: "+annotationMetadata);
        //輸出結果:annotationMetadata: com.example.test.bean.Color

        //獲取當前正在掃描的類的類信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        System.out.println("classMetadata: "+classMetadata);
        //輸出結果: classMetadata: com.example.test.bean.Color

        //獲取當前類資源(類的路徑)
        Resource resource = metadataReader.getResource();
        System.out.println("resource: "+resource);
        //輸出結果:resource: file [D:\idea\demo-02\target\classes\com\example\test\bean\Color.class]


        //獲取類名
        String className = classMetadata.getClassName();
        System.out.println("className: "+className);
        //輸出結果:className: com.example.test.bean.Color
        Class<?> forName = null;
        try {
            forName = Class.forName(className);
            if (Color.class.isAssignableFrom(forName)) {
                // 如果是Color的子類,就加載到IOC容器
                return true;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        System.out.println("========MtyTypeFilter===========");
        return false;
    }
}

5. @ComponentScans

可以一次聲明多個@ComponentScan

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)  //指定ComponentScan可以被ComponentScans作為數(shù)組使用
public @interface ComponentScan {
}
 
 
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ComponentScans {
    
	ComponentScan[] value();
 
}
@ComponentScans(value = { @ComponentScan(value = "com.example.test"),
		@ComponentScan(value = "com.example.test", includeFilters = {
				@Filter(type = FilterType.CUSTOM, value = MtyTypeFilter.class) }) })
public class MainConfig {
 
	@Bean(name = "pers", initMethod = "init", destroyMethod = "destory")
	public Person person() {
		return new Person();
	}
 
}

6. spring boot處理@ComponentScan源碼分析

spring創(chuàng)建bean對象的基本流程是先創(chuàng)建對應的BeanDefinition對象,然后在基于BeanDefinition對象來創(chuàng)建Bean對象,SpringBoot也是如此,只不過通過注解創(chuàng)建BeanDefinition對象的時機和解析方式不同而已。

SpringBoot是通過ConfigurationClassPostProcessor這個BeanFactoryPostProcessor類來處理。

本演示的demo涉及到4個演示類,分別是:

  1. 帶有@SpringBootApplication注解的啟動類Demo02Application。
  2. 帶有@RestController注解的類HelloController。
  3. 帶有@Configuration注解且有通過@Bean注解來創(chuàng)建addInterceptors的方法的MyMvcConfig類。
  4. Account實體類無任何注解。

本文的最后會貼出所有代碼。先從啟動類為入口,SpringBoot啟動類如下:

@SpringBootApplication
public class Demo02Application {

    public static void main(String[] args) {
        //1、返回我們IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(Demo02Application.class, args);
	}
}

從:

SpringApplication.run(Demo02Application.class, args);

一路斷點到核心方法

SpringApplication.ConfigurableApplicationContext run(String... args)

run方法干了兩件事:

  • 創(chuàng)建SpringApplication對象
  • 利用創(chuàng)建好的SpringApplication對象調用run方法
 public ConfigurableApplicationContext run(String... args) {
        long startTime = System.nanoTime();
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
        ConfigurableApplicationContext context = null;
        this.configureHeadlessProperty();
        //初始化監(jiān)聽器
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        //發(fā)布ApplicationStartingEven
        listeners.starting(bootstrapContext, this.mainApplicationClass);

        try {
        	 //裝配參數(shù)和環(huán)境
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //發(fā)布ApplicationEnvironmentPreparedEvent
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            //創(chuàng)建ApplicationContext,并裝配
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            //發(fā)布ApplicationPreparedEvent
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
            }
			//發(fā)布ApplicationStartedEven
            listeners.started(context, timeTakenToStartup);
            //執(zhí)行Spring中@Bean下的一些操作,如靜態(tài)方法
            this.callRunners(context, applicationArguments);
        } catch (Throwable var12) {
            this.handleRunFailure(context, var12, listeners);
            throw new IllegalStateException(var12);
        }

        try {
            Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
            listeners.ready(context, timeTakenToReady);
            return context;
        } catch (Throwable var11) {
            this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var11);
        }
    }

重點方法一:本方法法實現(xiàn)的重點功能:

  1. demoweb工程,springboot通過反射創(chuàng)建上下文context:AnnotationConfigServletWebServerApplicationContext
  2. 在構建context的無參構造方法中構建成員變量reader=new AnnotatedBeanDefinitionReader(this),在AnnotatedBeanDefinitionReader的無參構造方法中會beanFactory對象,并向beanFactory中注冊5個BeanDefinition對象,重點關注ConfigurationClassPostProcessor。
context = this.createApplicationContext();

重點方法二:本方法實現(xiàn)的重點功能本方法會構建啟動類Demo02Application對應的BeanDefinition對象,并注冊到beanFactory中,此時的context對象可見下圖

this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);

重點方法三:本方法實現(xiàn)的重點功能該方法實際調用applicationContext的refresh方法,本文后面只會分析ConfigurationClassPostProcessor對象的創(chuàng)建和postProcessBeanDefinitionRegistry方法的執(zhí)行

    this.refreshContext(context);
    this.afterRefresh(context, applicationArguments);
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);

代碼執(zhí)行后的截圖如下:

ConfigurationClassPostProcessor實現(xiàn)BeanFactoryPostProcessor,關于BeanFactoryPostProcessor擴展接口的作用在此處不做介紹。

ConfigurationClassPostProcessor對象的創(chuàng)建和方法執(zhí)行的斷點如下:

this.refreshContext(context);–> AbstractApplicationContext.refresh() --> invokeBeanFactoryPostProcessors() -->PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()->invokeBeanDefinitionRegistryPostProcessors()

下面重點看ConfigurationClassPostProcessor類的postProcessBeanDefinitionRegistry()方法如何處理@ComponentScan注解:

同過源代碼發(fā)現(xiàn)最終是由ConfigurationClassParser的解析類來處理,繼續(xù)查看ConfigurationClassParser.doProcessConfigurationClass

原來在這里對@ComponentScan注解做了判斷,上面一段代碼做了核心的幾件事:

  1. 掃描@ComponentScan注解包下面的所有的可自動裝備類,生成BeanDefinition對象,并注冊到beanFactory對象中。
  2. 通過DeferredImportSelectorHandler處理@EnableAutoConfiguration注解,后續(xù)會有專文介紹。
  3. 將帶有@Configuration 注解的類解析成ConfigurationClass對象并緩存,后面創(chuàng)建@Bean注解的Bean對象所對應的BeanDefinition時會用到到此為止MyFilter2對應的BeanDefinition已創(chuàng)建完畢。
  4. 如下圖:

總結

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • VSCode?配置?Spring?Boot?項目開發(fā)環(huán)境的全過程

    VSCode?配置?Spring?Boot?項目開發(fā)環(huán)境的全過程

    兩三年前曾經(jīng)試過配置Java環(huán)境, 存在不少問題作罷. 最近搜了下相關的文章, 感覺VSCode對Java項目的支持比三年前完善了不少. 今天實際配置了一下環(huán)境, 把自己常用的功能過了一遍, 基本能跑通開發(fā)流程, 做個筆記,需要的朋友可以參考下
    2024-03-03
  • maven profile實現(xiàn)多環(huán)境配置的示例

    maven profile實現(xiàn)多環(huán)境配置的示例

    這篇文章主要介紹了maven profile實現(xiàn)多環(huán)境配置的示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01
  • java用撲克牌計算24點

    java用撲克牌計算24點

    這篇文章主要為大家詳細介紹了java實現(xiàn)24點撲克牌游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • Java實現(xiàn)文件批量重命名具體實例

    Java實現(xiàn)文件批量重命名具體實例

    這篇文章主要介紹了Java實現(xiàn)文件批量重命名具體實例,需要的朋友可以參考下
    2014-02-02
  • java-RGB調色面板的實現(xiàn)(事件監(jiān)聽器之匿名內部類)

    java-RGB調色面板的實現(xiàn)(事件監(jiān)聽器之匿名內部類)

    這篇文章主要介紹了java-RGB調色面板的實現(xiàn)(事件監(jiān)聽器之匿名內部類),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-11-11
  • springboot整合quartz項目使用案例

    springboot整合quartz項目使用案例

    quartz是一個定時調度的框架,就目前市場上來說,其實有比quartz更優(yōu)秀的一些定時調度框架,不但性能比quartz好,學習成本更低,而且還提供可視化操作定時任務,這篇文章主要介紹了springboot整合quartz項目使用(含完整代碼),需要的朋友可以參考下
    2023-05-05
  • Java 讀取PDF中的文本和圖片的方法

    Java 讀取PDF中的文本和圖片的方法

    本文將介紹通過Java程序來讀取PDF文檔中的文本和圖片的方法。分別調用方法extractText()和extractImages()來讀取,需要的朋友可以參考下
    2019-07-07
  • 解讀為何java中的boolean類型是32位的

    解讀為何java中的boolean類型是32位的

    這篇文章主要介紹了為何java中的boolean類型是32位的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • Spring解決泛型擦除的思路詳解

    Spring解決泛型擦除的思路詳解

    這篇文章主要介紹了Spring解決泛型擦除的思路,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2024-01-01
  • Flink實現(xiàn)特定統(tǒng)計的歸約聚合reduce操作

    Flink實現(xiàn)特定統(tǒng)計的歸約聚合reduce操作

    這篇文章主要介紹了Flink實現(xiàn)特定統(tǒng)計的歸約聚合reduce操作,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧
    2023-02-02

最新評論