EnableAutoConfiguration注解的工作原理

demo

自己定义一个外部项目,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>

然后定义一个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容器了。

再定义一个springboot项目,加入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>

启动类启动:

@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);
    }
}

发现Cat类并没有纳入到springboot-enableAutoConfiguration项目中。

解决方案,
在core-bean项目resource下新建文件夹META-INF,在文件夹下面新建spring.factories文件,文件中配置,key为自定配置类EnableAutoConfiguration的全路径,value是配置类的全路径

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

启动springboot-enableAutoConfiguration项目,打印结果:

原理分析

进入EnableAutoConfiguration注解源码,发现是导入EnableAutoConfigurationImportSelector类,



跟到最后发现继承了ImportSelector接口,之前我们讲过 Springboot @Enable*注解的工作原理ImportSelector接口的selectImports返回的数组(类的全类名)都会被纳入到spring容器中。

其在AutoConfigurationImportSelector类中的selectImports实现,进入org.springframework.boot.autoconfigure.AutoConfigurationImportSelector类,

进入getCandidateConfigurations方法



getCandidateConfigurations会到classpath下的读取META-INF/spring.factories文件的配置,并返回一个字符串数组。

调试的时候读取到了core.bean.MyConfig,也读到了一些其他的配置,下面会讲。

图片.png

具体的就不细说了,有兴趣的朋友可以自己调试一下。
META-INF/spring.factories还可以配置多个配置类。

比如我们在core-bean下在定义二个类,

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项目的启动类:

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);
    }
}

打印结果如下:


发现都纳入到spring容器中了。

可以配置spring.boot.enableautoconfiguration=false禁用自动配置,这样不会启动自动配置了,默认是true。还可以排出一些自动配置类,可以在EnableAutoConfiguration注解加入参数,这边不做过多解释。

图片.png

总结,@EnableAutoConfiguration 作用
从classpath中搜索所有META-INF/spring.factories配置文件然后,将其中org.springframework.boot.autoconfigure.EnableAutoConfiguration key对应的配置项加载到spring容器
只有spring.boot.enableautoconfiguration为true(默认为true)的时候,才启用自动配置
@EnableAutoConfiguration还可以进行排除,排除方式有2中,一是根据class来排除(exclude),二是根据class name(excludeName)来排除
其内部实现的关键点有
1)ImportSelector 该接口的方法的返回值都会被纳入到spring容器管理中
2)SpringFactoriesLoader 该类可以从classpath中搜索所有META-INF/spring.factories配置文件,并读取配置

springboot内部如何使用@EnableAutoConfiguration注解

我们点进去spring-boot-autoconfigure中的META-INF下的spring.factories文件,发现spring.factories文件中配置了好多的配置类,在将这些依赖依赖到自己的项目中会将其都纳入到spring容器中,不过这些类好多都是配合@Conditional***等注解一起工作的。

举个例子:
在springboot-enableAutoConfiguration加入Gson依赖:

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

如果我们不在项目中配置,spring-boot-autoconfigure会自动帮我们装配一个对象实例名为gson的Gson实例。如果自己装配那么就使用自己装配的Gson实例。

启动测试类:

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));
    }
}

此时自己没有去配置Gson对象,

如果自己配置了,测试代码如下,启动:

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));
    }
}


作者:二月_春风
链接:https://www.jianshu.com/p/464d04c36fb1
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

猜你喜欢

转载自blog.csdn.net/qq_18416057/article/details/80845464