@EnableAutoConfiguration原理簡單分析

一、源碼分析簡述
聲明:本人使用的開發工具爲IDEA
1、@EnableAutoConfiguration瞭解

 查看源碼,眼睛掃到@Import(AutoConfigurationImportSelector.class),這很關鍵。注版本1.5是EnableAutoConfigurationImportSelector,該類繼承了AutoConfigurationImportSelector。

2、再查看源碼AutoConfigurationImportSelector.java,裏面用到了方法getCandidateConfigurations()
然後按住Ctrl點進去,查看方法getCandidateConfigurations(),瞭解他會到classpath下的讀取META-INF/spring.factories文件的配置,並返回一個字符串數組。這說明了@EnableAutoConfiguration-- 依賴於META-INF/spring.factories配置文件,spring.factories文件中鍵key爲 org.springframework.boot.autoconfigure.EnableAutoConfiguration ,對應的配置項(注:全類名)加載到spring容器。

  • 前提:只有spring.boot.enableautoconfiguration爲true(默認爲true)的時候,才啓用自動配置
  • 該註解@EnableAutoConfiguration還可以進行排除,排除方式有2中,一是根據classes來排除(exclude),二是根據class names(excludeName)來排除
  • 其內部實現的核心關鍵點有二

      1)ImportSelector 該接口的方法的返回值都會被納入到spring 的容器管理
      2)SpringFactoriesLoader 該類可以從classpath中搜索META-INF/spring.factories配置文件,並讀取配置
    

二、詳細步驟
1、創建兩個maven Module ,當然你也可以創建一個pom文件主要代碼如下

1)springboot3的maven module 的POM文件
 <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <junit.version>4.12</junit.version>
</properties>

<!--spring boot 環境:方法二:依賴管理加上導入import pom。代替繼承,注意 [scope,type]標籤-->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>1.5.10.RELEASE</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>


<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <!--依賴springboot03-core-bean-->
    <dependency>
        <groupId>com.fai</groupId>
        <artifactId>springboot03-core-bean</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <!--測試-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
    </dependency>
</dependencies>


2)springboot3-core-bean的maven module 的POM文件
<groupId>com.fai</groupId>
<artifactId>springboot03-core-bean</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <junit.version>4.12</junit.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.12.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
    </dependency>
</dependencies>

2、創建類

圖片描述



1)Car.java
    public class Car {}
    
2)CarConfiguration.java
    @Configuration
    public class CarConfiguration {
        @Bean
        public Car getCar() {
            return new Car();
        }
    }
    
3)Music.java
    public class Music {}

4)RunnableConfiguration.java
    /**
     * Runnable配置類
     */
    @Configuration
    public class RunnableConfiguration {
        @Bean
        public Runnable getRunnable1() {
            return () -> {};
        }
    }
    
5)META-INF/spring.factories
    #查看@EnableAutoConfiguration 註解源碼,--"spring.boot.enableautoconfiguration";
    #默認true . 如果改成false,EnableAutoConfiguration註解不起作用
    spring.boot.enableautoconfiguration=true
    
6)測試
    @EnableAutoConfiguration    // 根據應用所聲明的依賴來對Spring框架進行自動配置
    // 根據class排除
    //@EnableAutoConfiguration(exclude = {CarConfiguration.class,Music.class})
    // 根據class names排除,全類名
    //@EnableAutoConfiguration(excludeName = {"com.fai.bean.RunnableConfiguration"})
    @ComponentScan
    public class App {
    public static void main(String[] args) {
    SpringApplication app = new SpringApplication(App.class);
    ConfigurableApplicationContext context = app.run(args);

    // 獲取Runnable 類對象的實例
    // System.out.println(context.getBean(Runnable.class));
    System.out.println(context.getBeansOfType(Runnable.class));

    // 獲取Car 類的Bean
    System.out.println(context.getBeansOfType(Car.class));

    // 獲取Music 類的Bean
    System.out.println(context.getBeansOfType(Music.class));

    context.close();
    }
}



7)在測試中,更改配置文件application.properties中的spring.boot.enableautoconfiguration的值爲false後,獲取不到Bean
    #查看@EnableAutoConfiguration 註解源碼,"spring.boot.enableautoconfiguration";
    #默認true,如果改成false,EnableAutoConfiguration註解不起作用
    spring.boot.enableautoconfiguration=false
  

在第7)的改爲false測試結果如下圖,是空的。如果用getBean方法獲得Bean,會報錯,所以呀用的getBeansOfType方法。
圖片描述

三、附上關鍵源碼
1、@EnableAutoConfiguration 註解
@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class) // 1.5版本,我用的
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 {};

}

2、EnableAutoConfigurationImportSelector 源碼
@Deprecated
public class EnableAutoConfigurationImportSelector

    extends AutoConfigurationImportSelector {

@Override
protected boolean isEnabled(AnnotationMetadata metadata) {
    if (getClass().equals(EnableAutoConfigurationImportSelector.class)) {
        return getEnvironment().getProperty(
                EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class,
                true);
    }
    return true;
}

}

3、EnableAutoConfigurationImportSelector 的父類AutoConfigurationImportSelector 源碼關鍵方法摘要
@Override

public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) { // 配置文件中的默認配置爲true,我改過false的那個
        return NO_IMPORTS;
    }
    try {
        AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                .loadMetadata(this.beanClassLoader);
        AnnotationAttributes attributes = getAttributes(annotationMetadata);
        List<String> configurations = getCandidateConfigurations(annotationMetadata,
                attributes);
        configurations = removeDuplicates(configurations);
        configurations = sort(configurations, autoConfigurationMetadata);
        Set<String> exclusions = getExclusions(annotationMetadata, attributes);
        checkExcludedClasses(configurations, exclusions);
        configurations.removeAll(exclusions);
        configurations = filter(configurations, autoConfigurationMetadata);
        fireAutoConfigurationImportEvents(configurations, exclusions);
        return configurations.toArray(new String[configurations.size()]);
    }
    catch (IOException ex) {
        throw new IllegalStateException(ex);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章