springboot自动配置原理

 

Springboot自动配置原理

使用IDEA Spring Initializr快速创建一个Spring Boot项目

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {SpringApplication.run(MyApplication .class, args);}
}
我们看到,MyApplication作为入口类,入口类中有一个main方法,这个方法其实就是一个标准的Java应用的入口方法,一般在main方法中使用SpringApplication.run()来启动整个应用。值得注意的是,这个入口类要使用@SpringBootApplication注解声明,它是SpringBoot的核心注解。
@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 {
    //
}

@SpringBootApplication内部标注了三个注解:

@SpringBootConfiguration进入源码中可以看见,@SpringBootConfiguration其实就是Spring中的@Configuration,用于标注配置类

(SpringBootConfiguration是SpringBoot项目的配置注解,这也是一个组合注解,SpringBootConfiguration注解可以用java代码的形式实现spring中xml配置文件配置的效果,并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到spring容器中,并且实例名就是方法名。)

@ComponentScan这个注解也是Spring中的,它用来将指定包下需要装配的组件注册到容器中(@ComponentScan主要就是定义扫描的路径从中找出标识了需要装配的类自动装配到spring的bean容器中)
@EnableAutoConfiguration接下来才是今天的重头戏,Spring Boot自动配置的主角!
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    //
}
可以看到,在@EnableAutoConfiguration注解内使用到了@import注解来完成导入配置的功能,而EnableAutoConfigurationImportSelector内部则是使用了SpringFactoriesLoader.loadFactoryNames方法进行扫描具有META-INF/spring.factories文件的jar包。
 
@Import的作用就是导入一个类到IOC容器,我们先来看一下导入的这个类:自动配置导入选择器源码里有一个方法selectImports,选择导入

AutoConfigurationImportSelector中方法selectImports的源码如下:
 @Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    }
    try {
          AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                    .loadMetadata(this.beanClassLoader);
          AnnotationAttributes attributes = getAttributes(annotationMetadata);
          //扫描具有META-INF/spring.factories文件的jar包
          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);
    }
}
//加载spring.factories实现
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
        AnnotationAttributes attributes) {
    List<String> 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;
}
任何一个springboot应用,都会引入spring-boot-autoconfigure,而spring.factories文件就在该包下面。spring.factories文件是Key=Value形式,多个Value时使用,隔开,该文件中定义了关于初始化,监听器等信息,而真正使自动配置生效的key是org.springframework.boot.autoconfigure.EnableAutoConfiguration,如下所示:
该方法会去获取所有自动配置类的名称。
 
SpringFactoriesLoader类中给的loadFactoryNames的源码如下
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
可以看到该方法会扫描jar包路径下的META-INF/spring.factories 文件,把扫描到的这些文件内容包装成properties对象。再从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,并且把他们添加到容器中。
1)SpringBoot启动会加载大量的自动配置类
2)我们看我们需要的功能有没有SpringBoot默认写好的自动配置类;
3)我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件有,我们就不需要再来配置了)
4)给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可以在配置文件中指定这
些属性的值;
 
参考文章:
https://www.jianshu.com/p/4a6094542f45


 
posted on 2020-05-27 17:00  笑见蓝雨  阅读(145)  评论(0编辑  收藏  举报