EnableAutoConfiguration注解的工作原理

demo

自己定義一個(gè)外部項(xiàng)目,core-bean,依賴如下,

<artifactId>core-bean</artifactId>
<packaging>jar</packaging>

<dependencies>
   <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-context</artifactId>
       <version>4.3.9.RELEASE</version>
   </dependency>
</dependencies>

然后定義一個(gè)Cat類,

public class Cat {
}
package core.bean;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyConfig {

    @Bean
    public Cat cat(){
        return new Cat();
    }
}

我們知道這樣就將Cat類裝配到Spring容器了。

再定義一個(gè)springboot項(xiàng)目,加入core-bean依賴,依賴如下:

<artifactId>springboot-enableAutoConfiguration</artifactId>
<packaging>jar</packaging>

<dependencies>
     <dependency>
            <groupId>com.zhihao.miao</groupId>
            <artifactId>core-bean</artifactId>
            <version>1.0-SNAPSHOT</version>
      </dependency>
      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
     </dependency>
</dependencies>

啟動(dòng)類啟動(dòng):

@EnableAutoConfiguration
@ComponentScan
public class Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
        Cat cat = context.getBean(Cat.class);
        System.out.println(cat);
    }
}

發(fā)現(xiàn)Cat類并沒有納入到springboot-enableAutoConfiguration項(xiàng)目中。

解決方案,
在core-bean項(xiàng)目resource下新建文件夾META-INF,在文件夾下面新建spring.factories文件,文件中配置,key為自定配置類EnableAutoConfiguration的全路徑,value是配置類的全路徑

org.springframework.boot.autoconfigure.EnableAutoConfiguration=core.bean.MyConfig

啟動(dòng)springboot-enableAutoConfiguration項(xiàng)目,打印結(jié)果:

原理分析

進(jìn)入EnableAutoConfiguration注解源碼,發(fā)現(xiàn)是導(dǎo)入EnableAutoConfigurationImportSelector類,



跟到最后發(fā)現(xiàn)繼承了ImportSelector接口,之前我們講過Springboot @Enable*注解的工作原理ImportSelector接口的selectImports返回的數(shù)組(類的全類名)都會(huì)被納入到spring容器中。

其在AutoConfigurationImportSelector類中的selectImports實(shí)現(xiàn),進(jìn)入org.springframework.boot.autoconfigure.AutoConfigurationImportSelector類,

進(jìn)入getCandidateConfigurations方法



getCandidateConfigurations會(huì)到classpath下的讀取META-INF/spring.factories文件的配置,并返回一個(gè)字符串?dāng)?shù)組。

調(diào)試的時(shí)候讀取到了core.bean.MyConfig,也讀到了一些其他的配置,下面會(huì)講。

圖片.png

具體的就不細(xì)說了,有興趣的朋友可以自己調(diào)試一下。
META-INF/spring.factories還可以配置多個(gè)配置類。

比如我們?cè)赾ore-bean下在定義二個(gè)類,

package core.bean;

public class Dog {
}
package core.bean;

public class People {
}
package core.bean;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Myconfig2 {

    @Bean
    public Dog dog(){
        return new Dog();
    }
}

修改META-INF/spring.factories下的配置,

org.springframework.boot.autoconfigure.EnableAutoConfiguration=core.bean.MyConfig,core.bean.Myconfig2,core.bean.People

修改springboot-enableAutoConfiguration項(xiàng)目的啟動(dòng)類:

package com.zhihao.miao;

import core.bean.Cat;
import core.bean.Dog;
import core.bean.People;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@EnableAutoConfiguration
@ComponentScan
public class Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
        Cat cat = context.getBean(Cat.class);
        System.out.println(cat);
        Dog dog = context.getBean(Dog.class);
        System.out.println(dog);
        People people = context.getBean(People.class);
        System.out.println(people);
    }
}

打印結(jié)果如下:


發(fā)現(xiàn)都納入到spring容器中了。

可以配置spring.boot.enableautoconfiguration=false禁用自動(dòng)配置,這樣不會(huì)啟動(dòng)自動(dòng)配置了,默認(rèn)是true。還可以排出一些自動(dòng)配置類,可以在EnableAutoConfiguration注解加入?yún)?shù),這邊不做過多解釋。

圖片.png

總結(jié),@EnableAutoConfiguration 作用
從classpath中搜索所有META-INF/spring.factories配置文件然后,將其中org.springframework.boot.autoconfigure.EnableAutoConfiguration key對(duì)應(yīng)的配置項(xiàng)加載到spring容器
只有spring.boot.enableautoconfiguration為true(默認(rèn)為true)的時(shí)候,才啟用自動(dòng)配置
@EnableAutoConfiguration還可以進(jìn)行排除,排除方式有2中,一是根據(jù)class來排除(exclude),二是根據(jù)class name(excludeName)來排除
其內(nèi)部實(shí)現(xiàn)的關(guān)鍵點(diǎn)有
1)ImportSelector 該接口的方法的返回值都會(huì)被納入到spring容器管理中
2)SpringFactoriesLoader 該類可以從classpath中搜索所有META-INF/spring.factories配置文件,并讀取配置

springboot內(nèi)部如何使用@EnableAutoConfiguration注解

我們點(diǎn)進(jìn)去spring-boot-autoconfigure中的META-INF下的spring.factories文件,發(fā)現(xiàn)spring.factories文件中配置了好多的配置類,在將這些依賴依賴到自己的項(xiàng)目中會(huì)將其都納入到spring容器中,不過這些類好多都是配合@Conditional***等注解一起工作的。

舉個(gè)例子:
在springboot-enableAutoConfiguration加入Gson依賴:

<dependency>
      <groupId>com.google.code.gson</groupId>
       <artifactId>gson</artifactId>
</dependency>
GsonAutoConfiguration源碼

如果我們不在項(xiàng)目中配置,spring-boot-autoconfigure會(huì)自動(dòng)幫我們裝配一個(gè)對(duì)象實(shí)例名為gson的Gson實(shí)例。如果自己裝配那么就使用自己裝配的Gson實(shí)例。

啟動(dòng)測(cè)試類:

package com.zhihao.miao;

import com.google.gson.Gson;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
        System.out.println(context.getBeansOfType(Gson.class));
    }
}

此時(shí)自己沒有去配置Gson對(duì)象,

如果自己配置了,測(cè)試代碼如下,啟動(dòng):

package com.zhihao.miao;

import com.google.gson.Gson;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class Application {

    @Bean
    public Gson createGson(){
        return new Gson();
    }

    public static void main(String[] args) {
        ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
        System.out.println(context.getBeansOfType(Gson.class));
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容