国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

springboot源碼分析系列(三)--@EnableAutoConfiguration自動(dòng)配置加

Travis / 2204人閱讀

摘要:常規(guī)的配置讓開發(fā)人員將更多的經(jīng)歷耗費(fèi)在了配置文件上。其中有三個(gè)注解,,。以前我們需要配置的東西,幫我們自動(dòng)配置,告訴開啟自動(dòng)配置功能,這樣自動(dòng)配置才能生效。

為什么需要自動(dòng)化配置

??在常規(guī)的spring應(yīng)用程序中,充斥著大量的配置文件,我們需要手動(dòng)去配置這些文件,如配置組件掃描、視圖解析器、http編碼等等。常規(guī)的配置讓開發(fā)人員將更多的經(jīng)歷耗費(fèi)在了配置文件上。而這些配置都是一些固定模式的配置方式,甚至很多都是模板代碼。那既然是這樣一種情況,有沒有一種可能性,讓spring自動(dòng)完成這些模板配置工作呢?答案是肯定的,這就是SpringBoot AutoConfiguration產(chǎn)生的初衷。將開發(fā)人員從繁重的配置工作中解放出來,把這些繁瑣的配置交由SpringBoot完成,如果我們需要自己配置參數(shù),只需要覆蓋自動(dòng)配置的參數(shù)即可。

SpringBoot自動(dòng)化配置的核心原理

??在之前的文章中,我們看過了SpringBoot的核心注解@SpringBootApplication注解的源碼。其中有三個(gè)注解:@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan。以前我們需要配置的東西,SpringBoot幫我們自動(dòng)配置,@EnableAutoConfiguration告訴SpringBoot開啟自動(dòng)配置功能,這樣自動(dòng)配置才能生效。
??下面我們來分析一下@EnableAutoConfiguration這個(gè)注解的加載過程

Target(ElementType.TYPE)
Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    /**
     * Exclude specific auto-configuration classes such that they will never be applied.
     * @return the classes to exclude
     */
    Class[] exclude() default {};
    /**
     * Exclude specific auto-configuration class names such that they will never be
     * applied.
     * @return the class names to exclude
     * @since 1.3.0
     */
    String[] excludeName() default {};
}

??由源碼可知,@EnableAutoConfiguration是一個(gè)組合注解,由@AutoConfigurationPackage,@Import(AutoConfigurationImportSelector.class)這兩個(gè)注解組成。

@AutoConfigurationPackage

??@AutoConfigurationPackage的主要作用是自動(dòng)配置包

/**
 * Indicates that the package containing the annotated class should be registered with
 * {@link AutoConfigurationPackages}.
 *
 * @author Phillip Webb
 * @since 1.3.0
 * @see AutoConfigurationPackages
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

}
@Import(AutoConfigurationImportSelector.class)

??Spring底層注解@Import,給容器中導(dǎo)入一個(gè)組件;導(dǎo)入的組件由AutoConfigurationPackages.Registrar.class
將主配置類(@SpringBootApplication標(biāo)注的類)的所在包以及下面所有子包里面的所有組件掃描到Spring容器。
??AutoConfigurationImportSelector的作用是導(dǎo)入哪些組件的選擇器。將所有需要導(dǎo)入的組件以全類名的方式返回,這些組件就會(huì)被添加到容器中;也會(huì)給容器導(dǎo)入非常多的自動(dòng)配置類(xxxAutoConfiguration),就是給容器中導(dǎo)入這個(gè)場景需要的所有組件,并配置好這些組件。
??有了自動(dòng)配置類,免去了我們手動(dòng)編寫配置注入功能組件等的工作
具體的工作流程如下:

@EnableAutoConfiguration加載過程

??自動(dòng)配置主要由AutoConfigurationImportSelector實(shí)現(xiàn)的,我們主要從這個(gè)類開始講起。AutoConfigurationImportSelector是@EnableAutoConfiguration“@Import”的DeferredImportSelector實(shí)現(xiàn)類,由于DeferredImportSelector作為ImportSelector的子接口,所以組件自動(dòng)配置邏輯均在selectImports(AnnotationMetadata)方法中實(shí)現(xiàn)

??自動(dòng)配置加載過程主要分為以下幾個(gè)步驟:

1.判斷是否開啟自動(dòng)配置

2.從META-INF/spring-autoconfigure-metadata.properties文件中載入屬性配置

3.獲取所有的配置列表

public String[] selectImports(AnnotationMetadata annotationMetadata) {
    //1.是否開啟自動(dòng)配置,默認(rèn)開啟
    if (!isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    }
    //2.從META-INF/spring-autoconfigure-metadata.properties文件中載入屬性配置(有一些有默認(rèn)值),獲取注解信息
    AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
            .loadMetadata(this.beanClassLoader);
    //3.獲取所有的配置列表
    AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
            annotationMetadata);
    return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
1.是否開啟自動(dòng)配置,默認(rèn)開啟
protected boolean isEnabled(AnnotationMetadata metadata) {
    if (getClass() == AutoConfigurationImportSelector.class) {
        return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
    }
    return true;
}
2.從META-INF/spring-autoconfigure-metadata.properties文件中載入屬性配置
//文件為需要加載的配置類的類路徑
protected static final String PATH = "META-INF/" + "spring-autoconfigure-metadata.properties";

public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
    return loadMetadata(classLoader, PATH);
}

static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
    try {
        //1.讀取spring-boot-autoconfigure-2.1.6.RELEASE.jar包中pring-autoconfigure-metadata.properties的信息生成urls枚舉對象
        Enumeration urls = (classLoader != null) ? classLoader.getResources(path)
                : ClassLoader.getSystemResources(path);
        Properties properties = new Properties();
        //2.解析urls枚舉對象中的信息封裝成properties對象并加載
        while (urls.hasMoreElements()) {
            properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));
        }
        //3.根據(jù)封裝好的properties對象生成AutoConfigurationMetadata對象返回
        return loadMetadata(properties);
    }
    catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);
    }
}
3.獲取所有的配置列表
/**
 * Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata}
 * of the importing {@link Configuration @Configuration} class.
 * @param autoConfigurationMetadata the auto-configuration metadata
 * @param annotationMetadata the annotation metadata of the configuration class
 * @return the auto-configurations that should be imported
 */
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
        AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    //1.將注解元信息封裝成注解屬性對象
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    //2.獲取到配置類的全路徑字符串集合
    List configurations = getCandidateConfigurations(annotationMetadata, attributes);
    configurations = removeDuplicates(configurations);
    //需要排除的自動(dòng)裝配類(springboot的主類上 @SpringBootApplication(exclude = {com.demo.XXX.class})指定的排除的自動(dòng)裝配類)
    Set exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    //將需要排除的類從 configurations remove掉
    configurations.removeAll(exclusions);
    //過濾掉不需要裝配的類。過濾的邏輯有很多,比如我們常用的@ConditionXXX注解
    configurations = filter(configurations, autoConfigurationMetadata);
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
}
3.1將注解元信息封裝成注解屬性對象
/**
 * Return the appropriate {@link AnnotationAttributes} from the
 * {@link AnnotationMetadata}. By default this method will return attributes for
 * {@link #getAnnotationClass()}.
 * @param metadata the annotation metadata
 * @return annotation attributes
 */
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
    String name = getAnnotationClass().getName();
    AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
    Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
            + " annotated with " + ClassUtils.getShortName(name) + "?");
    return attributes;
}
3.2獲取到配置類的全路徑字符串集合

??getCandidateConfigurations(annotationMetadata, attributes);這個(gè)方法中有一個(gè)重要方法loadFactoryNames,這個(gè)方法是讓SpringFactoryLoader去加載一些組件的名字

/**
 * Return the auto-configuration class names that should be considered. By default
 * this method will load candidates using {@link SpringFactoriesLoader} with
 * {@link #getSpringFactoriesLoaderFactoryClass()}.
 * @param metadata the source metadata
 * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
 * attributes}
 * @return a list of candidate configurations
 */
protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    /**
     * 這個(gè)方法需要傳入兩個(gè)參數(shù)getSpringFactoriesLoaderFactoryClass()和getBeanClassLoader()
     * getSpringFactoriesLoaderFactoryClass()這個(gè)方法返回的是EnableAutoConfiguration.class
     * getBeanClassLoader()這個(gè)方法返回的是beanClassLoader(類加載器)
     */
    List configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
            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;
}

/**
 * Return the class used by {@link SpringFactoriesLoader} to load configuration
 * candidates.
 * @return the factory class
 */
protected Class getSpringFactoriesLoaderFactoryClass() {
    return EnableAutoConfiguration.class;
}

protected ClassLoader getBeanClassLoader() {
    return this.beanClassLoader;
}

??下面來看下loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),

        getBeanClassLoader());這個(gè)方法
public static List loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) {
    //factoryClassName為org.springframework.boot.autoconfigure.EnableAutoConfiguration
    String factoryClassName = factoryClass.getName();
    //該方法返回的是所有spring.factories文件中key為org.springframework.boot.autoconfigure.EnableAutoConfiguration的類路徑
    return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}

private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
    MultiValueMap result = (MultiValueMap)cache.get(classLoader);
    if(result != null) {
        return result;
    } else {
        try {
            //如果類加載器不為null,則加載類路徑下spring.factories文件,將其中設(shè)置的配置類的全路徑信息封裝 為Enumeration類對象
            Enumeration urls = classLoader != null?classLoader.getResources("META-INF/spring.factories"):ClassLoader.getSystemResources("META-INF/spring.factories");
            LinkedMultiValueMap result = new LinkedMultiValueMap();

            //循環(huán)Enumeration類對象,根據(jù)相應(yīng)的節(jié)點(diǎn)信息生成Properties對象,通過傳入的鍵獲取值,在將值切割為一個(gè)個(gè)小的字符串轉(zhuǎn)化為Array,方法result集合中
            while(urls.hasMoreElements()) {
                URL url = (URL)urls.nextElement();
                UrlResource resource = new UrlResource(url);
                //讀取文件內(nèi)容,properties類似于HashMap,包含了屬性的key和value
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                Iterator var6 = properties.entrySet().iterator();

                //屬性文件中可以用","分割多個(gè)value
                while(var6.hasNext()) {
                    Entry entry = (Entry)var6.next();
                    String factoryClassName = ((String)entry.getKey()).trim();
                    String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                    int var10 = var9.length;

                    for(int var11 = 0; var11 < var10; ++var11) {
                        String factoryName = var9[var11];
                        result.add(factoryClassName, factoryName.trim());
                    }
                }
            }

            cache.put(classLoader, result);
            return result;
        } catch (IOException var13) {
            throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
        }
    }
}
總結(jié)

??springboot底層實(shí)現(xiàn)自動(dòng)配置的步驟:

1.springboot應(yīng)用啟動(dòng)

2.@SpringBootApplication起作用

3.@EnableAutoConfiguration

4.@AutoConfigurationPackage:這個(gè)組合注解主要是@Import(AutoConfigurationPackages.Registrar.class),它通過將Registrar類導(dǎo)入到容器中,而Registrar類作用是掃描主配置類同級目錄以及子包,并將相應(yīng)的組件導(dǎo)入到springboot創(chuàng)建管理的容器中

5.@Import(AutoConfigurationImportSelector.class):它通過將AutoConfigurationImportSelector類導(dǎo)入到容器中,AutoConfigurationImportSelector類作用是通過selectImports方法實(shí)現(xiàn)將配置類信息交給SpringFactory加載器進(jìn)行一系列的容器創(chuàng)建過程,具體實(shí)現(xiàn)可查看上面的源碼

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/77916.html

相關(guān)文章

  • springboot源碼分析系列)--@EnableAutoConfiguration自動(dòng)配置

    摘要:常規(guī)的配置讓開發(fā)人員將更多的經(jīng)歷耗費(fèi)在了配置文件上。其中有三個(gè)注解,,。以前我們需要配置的東西,幫我們自動(dòng)配置,告訴開啟自動(dòng)配置功能,這樣自動(dòng)配置才能生效。 為什么需要自動(dòng)化配置 ??在常規(guī)的spring應(yīng)用程序中,充斥著大量的配置文件,我們需要手動(dòng)去配置這些文件,如配置組件掃描、視圖解析器、http編碼等等。常規(guī)的配置讓開發(fā)人員將更多的經(jīng)歷耗費(fèi)在了配置文件上。而這些配置都是一些固定模...

    macg0406 評論0 收藏0
  • SpringBoot源碼分析系列(一)--核心注解

    摘要:用于主類上最最最核心的注解,表示這是一個(gè)項(xiàng)目,用于開啟的各項(xiàng)能力。下面我們來分析一下這個(gè)注解的組成以及作用通過上面的代碼我們可以看出來是一個(gè)組合注解,主要由和這三個(gè)注解組成的。通過源碼可以看出也是一個(gè)組合注解。 ??SpringBoot項(xiàng)目一般都會(huì)有Application的入口類,入口類中會(huì)有main方法,這是一個(gè)標(biāo)準(zhǔn)的java應(yīng)用程序的入口方法。@SpringBootApplicat...

    seanlook 評論0 收藏0
  • @EnableAutoConfiguration原理簡單分析

    摘要:一源碼分析簡述聲明本人使用的開發(fā)工具為了解查看源碼,眼睛掃到,這很關(guān)鍵。注版本是,該類繼承了。這說明了依賴于配置文件,文件中鍵為對應(yīng)的配置項(xiàng)注全類名加載到容器。如果用方法獲得,會(huì)報(bào)錯(cuò),所以呀用的方法。 一、源碼分析簡述聲明:本人使用的開發(fā)工具為IDEA1、@EnableAutoConfiguration了解 查看源碼,眼睛掃到@Import(AutoConfigurationImpo...

    robin 評論0 收藏0
  • springboot(二)——springboot自動(dòng)配置解析

    摘要:前言用過的肯定很熟悉,它其中有個(gè)重要的特性,就是自動(dòng)配置平時(shí)習(xí)慣的一些設(shè)置的配置作為默認(rèn)配置。提倡無配置文件的理念,使用生成的應(yīng)用完全不會(huì)生成任何配置代碼與配置文件。 前言 用過springboot的肯定很熟悉,它其中有個(gè)重要的特性,就是自動(dòng)配置(平時(shí)習(xí)慣的一些設(shè)置的配置作為默認(rèn)配置)。springboot提倡無XML配置文件的理念,使用springboot生成的應(yīng)用完全不會(huì)生成任何配...

    張率功 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<