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

SpringBoot中自動(dòng)配置原理解析

 更新時(shí)間:2023年11月08日 10:52:22   作者:F?&?F  
SpringBoost是基于Spring框架開發(fā)出來的功能更強(qiáng)大的Java程序開發(fā)框架,本文將以廣角視覺來剖析SpringBoot自動(dòng)配置的原理,涉及部分Spring、SpringBoot源碼,需要的可以參考下

前言

SpringBoot作為當(dāng)前Java開發(fā)的熱門框架,有絞手架之稱。“約定大于配置”也一直是SpringBoot的標(biāo)簽,那么,SpringBoot要實(shí)現(xiàn)自身優(yōu)勢(shì),自動(dòng)配置功不可沒。

一、SpringBoot自動(dòng)配置是什么

SpringBoot自動(dòng)配置是指在應(yīng)用程序啟動(dòng)時(shí),SpringBoot根據(jù)classpath路徑下的jar包自動(dòng)配置應(yīng)用程序所需的一系列bean和組件,從而減少開發(fā)者的配置工作,提高開發(fā)效率。

二、@Import注解

在剖析SpringBoot自動(dòng)配置原理之前,我們先了解一下@Import注解的使用

1. 方式一: .class方式

定義兩個(gè)類A、B,并將其加入到Spring IOC容器中:

@Data
public class A{
	private Integer id=0;
	private String name="classA";
	public void print(){
		System.out.println(this.name);
	}
}

@Data
public class B{
	private Integer id=1;
	private String name="classB";
	public void print(){
		System.out.println(this.name);
	}
}

創(chuàng)建一個(gè)配置類,并使用@Import注解將類A、B添加到 IOC 容器中:

@Import({A.class,B.class})
@Configuration
public class ClassConfig{
???????}

2.方式二:ImportSelector方式

該方法需要定義類來實(shí)現(xiàn)ImportSelector接口,并重寫其中的selectImports( )方法,該方法的返回值是需要添加到IOC容器中的類的全限定類名數(shù)組:

@Data
public class C{
    private Integer id=2;
    private String name="classC";
    public void print(){
        System.out.println(this.name);
    }
}

編寫類來實(shí)現(xiàn)ImportSelector接口:

public class ImportSelectorTest implements ImportSelector{
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetada){
        return new String[]{"C.class"};
    }
}

使用該類:

@Import({ImportSelectorTest.class})
@Configuration
public class ImportSelectorConfig{
???????}

3.方式三:ImportBeanDefinitionRegistrar方式

定義一個(gè)類并實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口,重寫其中的registerBeanDefinitions( )方法,此方式可以自定義Bean在容器中的名稱:

@Data
public class D{
	private Integer id=3;
	private String name="ClassD";
	public void print(){
		System.out.println(this.name);
	}
}

//定義類實(shí)現(xiàn)ImPortBeanDefinitionRegistrar接口,重寫其中的registerBeanDefinitions()方法
public class ImportBeanDefinitionRegistrarTest{
	@Override
	public void registerBeanDefninitions(AnnotationMetadata annotationMetadata,BeanDefinitionRegistry registry{
		RootBeanDefinition rootBeanDefinition=new RootBeanDefinition(D.class);
		registry.registerBeanDefinition("自定義名稱",rootBeanDefinition);
	}
}

//使用上面的類進(jìn)行導(dǎo)入
@Import({ImportBeanDefinitionRegistrarTest})
@Configuration
public class ImportBeanDefinitionRegistrarConfig{

}

三、SpringBoot自動(dòng)配置原理解析

為了容易分析和理解,我們?cè)贗DEA中創(chuàng)建一個(gè)SpringBoot項(xiàng)目,創(chuàng)建過程省略,直接跳到該項(xiàng)目的主配置類進(jìn)行分析:

@SpringBootApplication
public class SpringBootTestApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootTestApplication.class, args);
    }

}

其中@SpringBootApplication注解是SpringBoot項(xiàng)目的重點(diǎn),按住ctrl鍵進(jìn)入其中,看到它由以下部分組成:

@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 {
    //內(nèi)容省略
}

我們主要關(guān)注以下幾個(gè)注解:

  • @SpringBootConfiguration:標(biāo)記當(dāng)前類為配置類
  • @EnableAutoConfiuration:開啟自動(dòng)配置
  • @ComponentScan:掃描主類所在包及其子包、同級(jí)包中的Bean

1、@SpringBootConfiguration注解:標(biāo)記當(dāng)前類為配置類

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

根據(jù)其源碼可以知道,@SpringBootConfiguration注解包含@Configuration,所以其擁有@Configuration注解相似的功能,而@Configuration注解又包含@Companent注解,所以配置類也存在于IOC容器中。

2、@EnableAutoConfiguration注解:開啟自動(dòng)配置

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

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

    String[] excludeName() default {};
}

根據(jù)其源碼得出其主要由@AutoConfigurationPackages注解和@Import注解組成

@AutoConfigurationPackages注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
    String[] basePackages() default {};

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

//其中的@Import注解導(dǎo)入了Registrar類,該類是AutoConfigurationPackages的靜態(tài)類部類
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        Registrar() {
        }

		/**
			根據(jù)傳入的元注解信息獲取所在的包,將包中組件類封裝為數(shù)組進(jìn)行注冊(cè)
		*/
        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
        }

        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
        }
    }

@Import({AutoConfigurationImportSelector.class})注解

這一步就用到了@Import注解使用方式中的第二中:實(shí)現(xiàn)ImportSelector接口

那么AutoConfigurationImportSelector接口何時(shí)如何被執(zhí)行呢?

SpringBoot 啟動(dòng)時(shí)會(huì)使用 ConfigurationClassParser 來解析被 @Configuration 標(biāo)識(shí)的配置類, 然后再處理這個(gè)類內(nèi)部被其他注解修飾的情況, 比如 @Import 注解, @ComponentScan 注解,@Bean 注解等

若發(fā)現(xiàn)注解中存在 @Import(ImportSelector) 的情況下,就會(huì)創(chuàng)建一個(gè)相應(yīng)的 ImportSelector 對(duì)象,并調(diào)用其 process 方法

public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
            Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> {
                return String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName());
            });
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector)deferredImportSelector).getAutoConfigurationEntry(annotationMetadata);
            this.autoConfigurationEntries.add(autoConfigurationEntry);
            Iterator var4 = autoConfigurationEntry.getConfigurations().iterator();

            while(var4.hasNext()) {
                String importClassName = (String)var4.next();
                this.entries.putIfAbsent(importClassName, annotationMetadata);
            }

        }

process方法又調(diào)用了getAutoConfigurationEntry方法:

protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

getAutoConfigurationEntry方法調(diào)用了getCandidateConfigurations方法:

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }

getCandidateConfigurations方法中使用了Spring Cor中的類SpringFactoriesLoader,該類的loadFactoryNames方法可以根據(jù)接口獲取接口類的名稱,這個(gè)方法返回的是類名的列表,loadFactoryNames方法會(huì)遍歷整個(gè)springboot項(xiàng)目的classpath下的ClassLoader中所有jar包下的spring.factories文件。至此自動(dòng)配置結(jié)束

總結(jié)

SpringBoot自動(dòng)配置是SpringBoot的核心,所以了解SpringBoot的自動(dòng)配置是非常有必要的,大家可以自行查找資料解釋以下為什么不使用@ComponentScan注解替換@Import注解來進(jìn)行類的導(dǎo)入

以上就是SpringBoot中自動(dòng)配置原理解析的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot自動(dòng)配置的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Spring Boot中捕獲異常錯(cuò)誤信息并將其保存到數(shù)據(jù)庫(kù)中的操作方法

    Spring Boot中捕獲異常錯(cuò)誤信息并將其保存到數(shù)據(jù)庫(kù)中的操作方法

    這篇文章主要介紹了Spring Boot中捕獲異常錯(cuò)誤信息并將其保存到數(shù)據(jù)庫(kù)中的操作方法,通過實(shí)例代碼介紹了使用Spring Data JPA創(chuàng)建一個(gè)異常信息的存儲(chǔ)庫(kù)接口,以便將異常信息保存到數(shù)據(jù)庫(kù),需要的朋友可以參考下
    2023-10-10
  • 簡(jiǎn)單實(shí)現(xiàn)Java版學(xué)生管理系統(tǒng)

    簡(jiǎn)單實(shí)現(xiàn)Java版學(xué)生管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了簡(jiǎn)單實(shí)現(xiàn)Java版學(xué)生管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-06-06
  • 為什么ConcurrentHashMap的key value不能為null,map可以?

    為什么ConcurrentHashMap的key value不能為null,map可以?

    這篇文章主要介紹了為什么ConcurrentHashMap的key value不能為null,map可以呢?具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • Java中notify是順序喚醒還是隨機(jī)喚醒的

    Java中notify是順序喚醒還是隨機(jī)喚醒的

    這篇文章主要介紹了Java中notify是順序喚醒還是隨機(jī)喚醒的,有很多人會(huì)認(rèn)為?notify?是隨機(jī)喚醒的,但它真的是隨機(jī)喚醒的嗎?帶著疑問一起進(jìn)入文章了解具體的內(nèi)容吧
    2022-05-05
  • java數(shù)組實(shí)現(xiàn)循環(huán)隊(duì)列示例介紹

    java數(shù)組實(shí)現(xiàn)循環(huán)隊(duì)列示例介紹

    大家好,本篇文章主要講的是java數(shù)組實(shí)現(xiàn)循環(huán)隊(duì)列示例介紹,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01
  • Java 自定義Spring框架以及Spring框架的基本使用

    Java 自定義Spring框架以及Spring框架的基本使用

    Spring框架是由于軟件開發(fā)的復(fù)雜性而創(chuàng)建的。Spring使用的是基本的JavaBean來完成以前只可能由EJB完成的事情。然而,Spring的用途不僅僅限于服務(wù)器端的開發(fā)
    2021-10-10
  • Spring?Boot?3.3?實(shí)現(xiàn)職責(zé)鏈模式輕松應(yīng)對(duì)電商訂單流程分析

    Spring?Boot?3.3?實(shí)現(xiàn)職責(zé)鏈模式輕松應(yīng)對(duì)電商訂單流程分析

    在電商系統(tǒng)中,訂單處理流程包括庫(kù)存校驗(yàn)、優(yōu)惠券驗(yàn)證、運(yùn)費(fèi)計(jì)算等多個(gè)步驟,這些步驟具有順序依賴性,為了管理這些業(yè)務(wù)邏輯,職責(zé)鏈模式提供了解決方案,通過鏈?zhǔn)疥P(guān)系將處理邏輯模塊化,實(shí)現(xiàn)解耦和靈活擴(kuò)展,本文將探討如何結(jié)合SpringBoot實(shí)現(xiàn)職責(zé)鏈模式,優(yōu)化電商訂單處理流程
    2024-10-10
  • 如何通過Java生成一個(gè)隨機(jī)數(shù)

    如何通過Java生成一個(gè)隨機(jī)數(shù)

    當(dāng)我們需要在Java中生成隨機(jī)數(shù)時(shí),可以借助JDK中提供的Random類來實(shí)現(xiàn),通過使用Random類,我們可以輕松地生成各種類型的隨機(jī)數(shù),下面我們就來看看如何利用Random類生成隨機(jī)數(shù)吧
    2023-09-09
  • Trae配置Java環(huán)境并運(yùn)行springboot項(xiàng)目的過程

    Trae配置Java環(huán)境并運(yùn)行springboot項(xiàng)目的過程

    本文給大家介紹Trae配置Java環(huán)境,運(yùn)行springboot項(xiàng)目的相關(guān)過程,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2026-02-02
  • Java將Date日期類型字段轉(zhuǎn)換成json字符串的方法

    Java將Date日期類型字段轉(zhuǎn)換成json字符串的方法

    這篇文章主要給大家介紹了關(guān)于Java將Date日期類型字段轉(zhuǎn)換成json字符串的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02

最新評(píng)論

文水县| 乐昌市| 靖安县| 庄河市| 瓦房店市| 罗山县| 梧州市| 秦安县| 呈贡县| 读书| 深水埗区| 青冈县| 德令哈市| 开江县| 永济市| 大余县| 金坛市| 秭归县| 寿宁县| 灵石县| 宜昌市| 澄江县| 中方县| 寿光市| 安西县| 安远县| 隆化县| 临夏市| 介休市| 沂南县| 香港 | 伊通| 喜德县| 新化县| 蒲江县| 广州市| 镇安县| 大余县| 松溪县| 轮台县| 顺平县|